Sorting elements in a list of lists - python

Hey I have a list that goes like:
List = [[[1,2],[4,5,3]],[[5,2],[3,4,7]],...]
and I want to sort the elements of each sublist, that the output looks like:
List = [[[2,1],[5,4,3]],[[5,2],[7,4,3]],...]
What I have already tried is creating a loop like this.
for i in List:
for u in [i]:
List[u].sort(reverse = True)
print(List)
but it didnt worked. In other Blogposts I just found ways how to sort the lists, but not the elements in them.
Thanks for your help

You are close, just a few things wrong:
for u in [i]: Do not wrap i in brackets. You are just creating a new list with i as its only element, and looping over that which is not what you want.
Second:
List[u].sort(reverse = True) You do not need to do List[u], rather just u, because inside of this loop, u is equal to the sublist that you want to sort
Also a side note, variables should be lowercase
myList = [[[1,2],[4,5,3]],[[5,2],[3,4,7]]]
for i in myList:
for u in i:
u.sort(reverse=True)
print(myList)

You may use a list comprehension, to easily retrieve the values, iterate over each sublist and sort the subsublist
values = [[[1, 2], [4, 5, 3]], [[5, 2], [3, 4, 7]]]
values = [[sorted(subsub, reverse=True) for subsub in sub] for sub in values]
print(values) # [[[2, 1], [5, 4, 3]], [[5, 2], [7, 4, 3]]]
Or with loops, you can just access the inner lists with the second loop and inline sort them
for sub in values:
for subsub in sub:
subsub.sort(reverse=True)
Note: use meaningful names to your variables

You are close with your approach although in your second loop you’re enclosing i in a list which won’t loop through each sub list and you only need to sort u as you’re not going to slice a list with a list.
for i in List:
for u in i:
u.sort(reverse = True)
print(List)
Result:
[[[2, 1], [5, 4, 3]], [[5, 2], [7, 4, 3]]]
PS If there could be only one layer of nesting then I'd suggest using isinstance to check before looping through and error-ing out due to attempting to sort an int
for i in List:
if isinstance(i[0], list):
for u in i:
u.sort(reverse = True)
else:
i.sort(reverse = True)

Another approach using list comprehension (one liner):
li = [[[1,2],[4,5,3]],[[5,2],[3,4,7]]]
li = [[sorted(i, reverse=True) for i in j] for j in li]
print(li)
Output:
[[[2, 1], [5, 4, 3]], [[5, 2], [7, 4, 3]]]

Is this what you are looking for?
for i in List:
for u in i:
u.sort(reverse = True)

You can use Pandas to sort your data.
import pandas as pd
ist = [[[1,2],[4,5,3]],[[5,2],[3,4,7]]]
df = pd.DataFrame(ist)
I named the columns to read the columns easier.
df.columns = ['a', 'b']
Now we can sort the elements of the lists in each,
df['a'] = df.a.apply(lambda x: sorted(x,reverse=True))
df['b'] = df.b.apply(lambda x: sorted(x,reverse=True))
which yields,
print(df.head())
a b
0 [2, 1] [5, 4, 3]
1 [5, 2] [7, 4, 3]

Related

Saving result of nested list comprehension

I would like to store intermediate results from a nested list comprehension in sublists so that the result looks like this:
example_list = [[[1,2,3], [1,2,3]], [[2,3,4], [2,3,4]]];
sink = [];
for sl in example_list :
temp = [];
for ssl in sl :
temp.append(np.mean(ssl));
sink.append(temp);
expected_result = [[2,2], [3,3]];
How do you perform this using a list comprehension?
I tried something like this, but obviously it doesn't work, I'm blocked on the syntax:
sink = [[np.mean(j)] for i in example_list for j in i];
Not sure what the challenge is. You can create a nested loop within the list. comprehension and store the values.
Here's what I did:
x = [[[i*j*k for i in range (1,4)] for j in range(1,4)] for k in range(1,3)]
print (x)
Output is:
[[[1, 2, 3], [2, 4, 6], [3, 6, 9]], [[2, 4, 6], [4, 8, 12], [6, 12, 18]]]
If you can give me a good use case, it can be implemented.
In the meanwhile, let me see if I can grab some data and show you the implementation.
you can try this;
final_list=[[int(np.mean(ssl)) for ssl in sl] for sl in example_list]
print(final_list)
output:
[[2, 2], [3, 3]]

Removing duplicates from a list of lists based on a comparison of an element of the inner lists

I have a large list of lists and need to remove duplicate elements based on specific criteria:
Uniqueness is determined by the first element of the lists.
Removal of duplicates is determined by comparing the value of the second element of the duplicate lists, namely keep the list with the lowest second element.
[[1, 4, 5], [1, 3, 4], [1, 2, 3]]
All the above lists are considered duplicates since their first elements are equal. The third list needs to be kept since it's second element is the smallest. Note the actual list of lists has over 4 million elements, is double sorted and ordering needs to be preserved.
The list is first sorted based on the second element of the inner lists and in reverse (descending) order, followed by normal (ascending) order based on the first element:
sorted(sorted(the_list, key=itemgetter(1), reverse=True), key=itemgetter(0))
An example of three duplicate lists in their actual ordering:
[...
[33554432, 50331647, 1695008306],
[33554432, 34603007, 1904606324],
[33554432, 33554687, 2208089473],
...]
The goal is to prepare the list for bisect searching. Can someone provide me with insight on how this might be achieved using Python?
You can group the elements using a dict, always keeping the sublist with the smaller second element:
l = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [2, 4, 3], [2, 5, 6], [2, 1, 3]]
d = {}
for sub in l:
k = sub[0]
if k not in d or sub[1] < d[k][1]:
d[k] = sub
Also you can pass two keys to sorted, you don't need to call sorted twice:
In [3]: l = [[1,4,6,2],[2,2,4,6],[1,2,4,5]]
In [4]: sorted(l,key=lambda x: (-x[1],x[0]))
Out[4]: [[1, 4, 6, 2], [1, 2, 4, 5], [2, 2, 4, 6]]
If you wanted to maintain order in the dict as per ordering needs to be preserved.:
from collections import OrderedDict
l = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [2, 4, 3], [2, 5, 6], [2, 1, 3]]
d = OrderedDict()
for sub in l:
k = sub[0]
if k not in d or sub[1] < d[k][1]:
d[sub[0]] = sub
But not sure how that fits as you are sorting the data after so you will lose any order.
What you may find very useful is a sortedcontainers.sorteddict:
A SortedDict provides the same methods as a dict. Additionally, a SortedDict efficiently maintains its keys in sorted order. Consequently, the keys method will return the keys in sorted order, the popitem method will remove the item with the highest key, etc.
An optional key argument defines a callable that, like the key argument to Python’s sorted function, extracts a comparison key from each dict key. If no function is specified, the default compares the dict keys directly. The key argument must be provided as a positional argument and must come before all other arguments.
from sortedcontainers import SortedDict
l = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [2, 4, 3], [2, 5, 6], [2, 1, 3]]
d = SortedDict()
for sub in l:
k = sub[0]
if k not in d or sub[1] < d[k][1]:
d[k] = sub
print(list(d.values()))
It has all the methods you want bisect, bisect_left etc..
If I got it correctly, the solution might be like this:
mylist = [[1, 2, 3], [1, 3, 4], [1, 4, 5], [7, 3, 6], [7, 1, 8]]
ordering = []
newdata = {}
for a, b, c in mylist:
if a in newdata:
if b < newdata[a][1]:
newdata[a] = [a, b, c]
else:
newdata[a] = [a, b, c]
ordering.append(a)
newlist = [newdata[v] for v in ordering]
So in newlist we will receive reduced list of [[1, 2, 3], [7, 1, 8]].

Remove a column from a nested list in Python

I need help figuring how to work around removing a 'column' from a nested list to modify it.
Say I have
L = [[1,2,3,4],
[5,6,7,8],
[9,1,2,3]]
and I want to remove the second column (so values 2,6,1) to get:
L = [[1,3,4],
[5,7,8],
[9,2,3]]
I'm stuck with how to modify the list with just taking out a column. I've done something sort of like this before? Except we were printing it instead, and of course it wouldn't work in this case because I believe the break conflicts with the rest of the values I want in the list.
def L_break(L):
i = 0
while i < len(L):
k = 0
while k < len(L[i]):
print( L[i][k] , end = " ")
if k == 1:
break
k = k + 1
print()
i = i + 1
So, how would you go about modifying this nested list?
Is my mind in the right place comparing it to the code I have posted or does this require something different?
You can simply delete the appropriate element from each row using del:
L = [[1,2,3,4],
[5,6,7,8],
[9,1,2,3]]
for row in L:
del row[1] # 0 for column 1, 1 for column 2, etc.
print L
# outputs [[1, 3, 4], [5, 7, 8], [9, 2, 3]]
If you want to extract that column for later use, while removing it from the original list, use a list comprehension with pop:
>>> L = [[1,2,3,4],
... [5,6,7,8],
... [9,1,2,3]]
>>>
>>> [r.pop(1) for r in L]
[2, 6, 1]
>>> L
[[1, 3, 4], [5, 7, 8], [9, 2, 3]]
Otherwise, just loop over the list and delete the fields you no longer want, as in arshajii's answer
You can use operator.itemgetter, which is created for this very purpose.
from operator import itemgetter
getter = itemgetter(0, 2, 3) # Only indexes which are needed
print(list(map(list, map(getter, L))))
# [[1, 3, 4], [5, 7, 8], [9, 2, 3]]
You can use it in List comprehension like this
print([list(getter(item)) for item in L])
# [[1, 3, 4], [5, 7, 8], [9, 2, 3]]
You can also use nested List Comprehension, in which we skip the elements if the index is 1, like this
print([[item for index, item in enumerate(items) if index != 1] for items in L])
# [[1, 3, 4], [5, 7, 8], [9, 2, 3]]
Note: All these suggested in this answer will not affect the original list. They will generate new lists without the unwanted elements.
Use map-lambda:
print map(lambda x: x[:1]+x[2:], L)
Here is one way, updated to take in kojiro's advice.
>>> L[:] = [i[:1]+i[2:] for i in L]
>>> L
[[1, 3, 4], [5, 7, 8], [9, 2, 3]]
You can generalize this to remove any column:
def remove_column(matrix, column):
return [row[:column] + row[column+1:] for row in matrix]
# Remove 2nd column
copyofL = remove_column(L, 1) # Column is zero-base, so, 1=second column
when you do the del it will delete that index and reset the index, so you have to reduce that index. Here I use the count to reduce and reset the same from the index list we have. Hope this helps. Thanks
nested_list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
remove_cols_index = [1,2]
count = 0
for i in remove_cols_index:
i = i-count
count = count+1
del nested_list[i]
print (nested_list)
[j.pop(1) for j in nested_list]
from https://www.geeksforgeeks.org/python-column-deletion-from-list-of-lists/

Check item membership in set in Python

Hello I've been coding for a couple of months now and know the basics, but I'm having a set membership problem for which I can't find a solution.
I have a list of lists of pairs of integers, and I want to remove the list that have the "a" integer in them. I thought using sets was the easiest way. Bellow is the code:
## This is the item to test against.
a = set([3])
## This is the list to test.
groups = [[3, 2], [3, 4], [1, 2], [5, 4], [4, 3]]
## This is a list that will contain the lists present
## in groups which do not contain "a"
groups_no_a = []
for group in groups:
group = set(group)
if a in group:
groups_no_a.append(group)
## I thought the problem had something to do with
## clearing the variable so I put this in,
## but to no remedy.
group.clear()
print groups_no_a
I had also tried using s.issubset(t) until I realized that this tested if every element in s in t.
Thank you!
You want to test if there is no intersection:
if not a & group:
or
if not a.intersection(group):
or, inversely, that the sets are disjoint:
if a.isdisjoint(group):
The method forms take any iterable, you don't even have to turn group into a set for that. The following one-liner would work too:
groups_no_a = [group for group in groups if a.isdisjoint(group)]
Demo:
>>> a = set([3])
>>> groups = [[3, 2], [3, 4], [1, 2], [5, 4], [4, 3]]
>>> [group for group in groups if a.isdisjoint(group)]
[[1, 2], [5, 4]]
If all you are testing for is one element, then it could be that creating sets is going to cost more in performance than what you gain in testing for membership, and just doing:
3 not in group
where group is a short list.
You can use the timeit module to compare pieces of Python code to see what works best for your specific typical list sizes.
Maybe you could use List Comprehension:
a = 3
groups = [[3, 2], [3, 4], [1, 2], [5, 4], [4, 3]]
print [x for x in groups if a not in x]
Edit based on a comment:
Well to those curious, what I want to do is; I have a list like the
following: [ [error, [ [group_item_1, group_item_2], [...], [...],
[...] ] ], [more like this previous], [...] ], and I want to get the
item with least error and that doesn't have "a" in group_item_1 or
group_item_2. The lists are already sorted by error. I sorta almost go
it :D
This should do the trick:
from itertools import chain, iterfilter
def flatten(listOfLists):
"Flatten one level of nesting"
return chain.from_iterable(listOfLists)
errors_list = [ ['error0', [ [30, 2], [3, 4], [1, 2], [5, 4], [4, 3] ] ], ['error1', [ [31, 2], [3, 4], [1, 2], [5, 4], [4, 3] ] ] ]
a = 30
result = next(ifilter(lambda err: a not in flatten(err[1]), reversed(errors_list)), None)
print result #finds error1 as it has no 30 on its list
Rather than making a = set([3]), why not do the following?
a = 3
groups = [[3, 2], [3, 4], [1, 2], [5, 4], [4, 3]]
groups_no_a = [group for group in groups if a not in group]
You don't need to use sets here, you can test for membership of elements in lists. You also seem to have in, where I think you should have not in.
This code is similar to yours, and should work:
## This is the item to test against.
a = 3
## This is the list to test.
groups = [[3, 2], [3, 4], [1, 2], [5, 4], [4, 3]]
## This is a list that will contain the lists present
## in groups which do not contain a
groups_no_a = []
for group in groups:
if a not in group:
groups_no_a.append(group)
print groups_no_a
However, a shorter, more Pythonic way uses list comprehensions:
groups_no_a = [i for i in groups if a not in i]
If you are testing a whether an item is in a much longer list, you should use sets instead for performance.

Python: One-liner to perform an operation upon elements in a 2d array (list of lists)?

I have a list of lists, each containing a different number of strings. I'd like to (efficiently) convert these all to ints, but am feeling kind of dense, since I can't get it to work out for the life of me. I've been trying:
newVals = [int(x) for x in [row for rows in values]]
Where 'values' is the list of lists. It keeps saying that x is a list and can therefore not be the argument if int(). Obviously I'm doing something stupid here, what is it? Is there an accepted idiom for this sort of thing?
This leaves the ints nested
[map(int, x) for x in values]
If you want them flattened, that's not hard either
for Python3 map() returns an iterator. You could use
[list(map(int, x)) for x in values]
but you may prefer to use the nested LC's in that case
[[int(y) for y in x] for x in values]
How about:
>>> a = [['1','2','3'],['4','5','6'],['7','8','9']]
>>> [[int(j) for j in i] for i in a]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Another workaround
a = [[1, 2, 3], [7, 8, 6]]
list(map(lambda i: list(map(lambda j: j - 1, i)), a))
[[0, 1, 2], [6, 7, 5]] #output
You simply use incorrect order and parenthesis - should be:
inputVals = [['1','2','3'], ['3','3','2','2']]
[int(x) for row in inputVals for x in row]
Or if you need list of list at the output then:
map(lambda row: map(int, row), inputVals)
an ugly way is to use evalf:
>>> eval(str(a).replace("'",""))
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
if you don't mind all your numbers in one array you could go:
>>> a = [['1','2','3'],['4','5','6'],['7','8','9']]
>>> map(int,sum(a,[]))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
In order to map list with any number of dimensions you could use numpy.apply_over_axes
import numpy as np
np.apply_over_axes(lambda x,_:x*2, np.array([[1,2,3],[5,2,1]]),[0])
--------------------
array([[ 2, 4, 6],
[10, 4, 2]])
Unfortunately that doesn't work if you also need to change variable type. Didn't find any library solution for this, so here is the code to do that:
def map_multi_dimensional_list(l, transform):
if type(l) == list and len(l) > 0:
if type(l[0]) != list:
return [transform(v) for v in l]
else:
return [map_multi_dimensional_list(v, transform) for v in l]
else:
return []
map_multi_dimensional_list([[[1,2,3],[5,2,1]],[[10,20,30],[50,20,10]]], lambda x:x*2)
------------------
[[[2, 4, 6], [10, 4, 2]], [[20, 40, 60], [100, 40, 20]]]

Categories