Sorting Key in Python3 [duplicate] - python

This question already has answers here:
Sort list of lists ascending and then descending [duplicate]
(3 answers)
Closed 3 years ago.
I have a list of lists as myList = [['a',1],['b',4],['a',5], ['b',6]].I want to sort this list alphabetically with first element as the key which I can do as myList.sort(key=lambda x:x[0]) which changes myList to [['a', 1], ['a', 5], ['b', 4], ['b',6]]. But if the first elements of the inner lists are the same, I want to sort it in descending order of the second element of the inner list and get the result as [['a', 5], ['a', 1], ['b', 6], ['b',4]]. What is the cleaner way to do it? I could have done this in Javascript as
myList.sort((a,b) => {
if(a[0] == b[0]){
return b[1] > a[1]
} else {
return b[0] < a[0]
}
})
How do I achieve this in python?

Use a tuple as a key:
myList.sort(key=lambda x:(x[0], -x[1]))
# myList = [['a', 5], ['a', 1], ['b', 6], ['b', 4]]

Related

Extending lists of lists [duplicate]

This question already has answers here:
Why do these list operations (methods: clear / extend / reverse / append / sort / remove) return None, rather than the resulting list?
(6 answers)
How do I iterate through two lists in parallel?
(8 answers)
How do I concatenate two lists in Python?
(31 answers)
Closed 6 months ago.
I'm trying to extend two lists of lists in python, so that item 1 of the first list of lists extends with item 1 of the second list of lists, and so forth.
I'm new to this and self-taught, so could be missing something very simple, but I can't find an answer anywhere.
This is what I feel the code should be, but obviously not working.
list1[x].extend(list2[x]) for x in list1
What I'm trying to achieve is this:
list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = [[a,b,c],[d,e,f],[g,h,i]]
output = [[1,2,3,a,b,c],[4,5,6,d,e,f],[7,8,9,g,h,i]]
Any ideas?
You can use zip:
list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = [['a','b','c'], ['d','e','f'], ['g','h','i']]
output = [sub1 + sub2 for sub1, sub2 in zip(list1, list2)]
print(output)
# [[1, 2, 3, 'a', 'b', 'c'], [4, 5, 6, 'd', 'e', 'f'], [7, 8, 9, 'g', 'h', 'i']]
Use zip() to loop over the two lists in parallel. Then use extend() to append the sublist from list2 to the corresponding sublist in list1.
for l1, l2 in zip(list1, list2):
l1.extend(l2)
print(list1)
list1[x].extend(list2[x]) does achieve the result you want for one pair of lists, if list1[x] is [1, 2, 3] and list2[x] is [a, b, c], for example.
That means x has to be an index:
x = 0
list1[x].extend(list2[x])
# now the first list in `list1` looks like your desired output
To do that for every pair of lists, loop over all possible indexes x – range(upper) is the range of integers from 0 (inclusive) to upper (exclusive):
for x in range(len(list1)):
list1[x].extend(list2[x])
# now `list1` contains your output
To produce a new list of lists instead of altering the lists in list1, you can concatenate lists with the + operator instead:
>>> [1, 2, 3] + ['a', 'b', 'c']
[1, 2, 3, 'a', 'b', 'c']
output = []
for x in range(len(list1)):
output.append(list1[x] + list2[x])
And finally, the idiomatic Python for this that you’ll get around to someday is:
output = [x1 + x2 for x1, x2 in zip(list1, list2)]
I have simply used list comprehension with list addition, while zipping the correlated lists together
list1 = [[1,2,3],[4,5,6],[7,8,9]]
list2 = [['a','b','c'], ['d','e','f'], ['g','h','i']]
list3 = [l1+l2 for l1, l2 in zip(list1, list2)]
print(list3)
[[1, 2, 3, 'a', 'b', 'c'], [4, 5, 6, 'd', 'e', 'f'], [7, 8, 9, 'g', 'h', 'i']]

Function that can apply list changes to other lists [duplicate]

This question already has answers here:
Sorting list based on values from another list
(20 answers)
Closed 1 year ago.
I am searching for a function that can apply position changes in a list to other lists.
For example:
liste1 = [3, 4, 1]
liste2 = ['a', 'b', 'c']
liste1.sort() #so liste1 = [1,3,4]
if liste1 = [1,3,4] :
liste2 = ['c', 'a', 'b']
I can change positions of liste2 myself, but I have 270,000 values, which is why I am searching for a function that can do it.
You could zip the lists together, sort them then unzip them.
liste1 = [3, 4, 1]
liste2 = ['a', 'b', 'c']
merged_lists = sorted(zip(liste1, liste2))
liste1, liste2 = zip(*merged_lists)
print(liste1, liste2, sep="\n")
OUTPUT
(1, 3, 4)
('c', 'a', 'b')

comparing elements of a list of list and removing

l=[['a', 'random_str', 4], ['b', 'random_str2', 5], ['b', 'random_str3', 7]]
so I have a list like this and I want to traverse through this list to check if the zeroth index of each sublist is equivalent to one another so check if any zeroth index of each sublist is equal to another, and then if two of or more are similar check the second index in the sublist and only keep the sublist with lowest int value and remove all others.
so the output should be that
[['a', 'random_str', 4], ['b', 'random_str2', 5]]
so it removes the sublist with the higher int in the second index
I'm thinking something like this
for i in l:
for k in i:
if k[0]=i[0][0]:
# then I dont know
It can be achieved with pandas, a sort_values and a groupby:
import pandas as pd
l=[['a', 'random_str', 4], ['b', 'random_str2', 5], ['b', 'random_str3', 7]]
#create dataframe from list of list
df = pd.DataFrame(l)
#sort column based on third column / index = 2
df = df.sort_values(by=2)
#groupby first column and only take first entry which is lowest int after sort.
df = df.groupby(0).head(1)
#put back to list of list
df = df.values.tolist()
print(df)
prints out
[['a', 'random_str', 4], ['b', 'random_str2', 5]]
One more option may be this:
l = [['a', 'random_str', 4], ['b', 'random_str2', 5], ['b', 'random_str3', 7]]
# initialize a dict
d = {x[0]: list() for x in l}
# lambda function to compare values
f = lambda x: x if not d[x[0]] or x[2] < d[x[0]][2] else d[x[0]]
# list comprehension to iterate and process the list of values
[d.update({x[0]: f(x)}) for x in l]
# output exected: [['a', 'random_str', 4], ['b', 'random_str2', 5]]
print(list(d.values()))
This list-comprehension is fairly horrible, but does what you're after - find the minimum element based on third element, for every sublist with first element iterating over a set of first elements.
>>> [min((x for x in l if x[0] == y), key=lambda x: x[2]) for y in set(z[0] for z in l)]
[['b', 'random_str2', 5], ['a', 'random_str', 4]]
Group by first element, and in each group find min by third:
f2 = lambda x: x[2]
f0 = lambda x: x[0]
[min(subl, key=f2) for _, subl in itertools.groupby(sorted(l, key=f0), key=f0)]
# => [['a', 'random_str', 4], ['b', 'random_str2', 5]]
not so good/pythonic way, but you can use dictionary to get result
l=[['a', 'random_str', 4], ['b', 'random_str2', 5], ['b', 'random_str3', 7]]
res = {}
for sublist in l:
if sublist[0] not in res.keys():
res.update({sublist[0]:[sublist[1], sublist[2]]})
else:
if sublist[2]<res[sublist[0]][1]:
res[sublist[0]][1] = sublist[2]
final_res = [[index, res[index][0], res[index][1]] for index, value in res.items()]
print(final_res)
output
[['a', 'random_str', 4], ['b', 'random_str2', 5]]
This should do the trick. (I'm sure you could reduce the time complexity with a clever algorithm that does not sort, but unless we're talking about a bottleneck here you should not be too concerned about that.)
>>> from itertools import groupby
>>> from operator import itemgetter
>>>
>>> first, third = itemgetter(0), itemgetter(2)
>>> l = [['a', 'random_str', 4], ['b', 'random_str2', 5], ['b', 'random_str3', 7]]
>>>
>>> groups = groupby(sorted(l), key=first)
>>> [min(list(group), key=third) for _, group in groups]
[['a', 'random_str', 4], ['b', 'random_str2', 5]]
The idea is to group your data by the first element in each sublist. groupby needs l to be sorted in order to do that. (sorted already sorts lexicographically, but you could optimize it by using sorted(l, key=first) such that only the first element is considered for sorting.) Afterwards, we extract the minimum of each group with respect to element three (index 2).
All of this could be done in one line, but I find groupby oneliners terribly unreadable, so I opted for a solution with more lines and some self-documenting variable names.
Doing this via dataframe is the easiest and most efficient according to me. Try
import pandas as pd
data = [['a', 'random_str4', 4], ['b', 'random_str2', 5], ['b', 'random_str3', 7], ['a', 'random_str2', 6]]
df = pd.DataFrame(data)
df = df.sort_values(by = 2)
df = df.drop_duplicates(0)
df.values.tolist()
This outputs the desired result, i.e.,
[['a', 'random_str4', 4], ['b', 'random_str2', 5]]
I know this is not the most feasible solution, but works fine for the mean time.
Assuming the list is sorted in Ascending order,
def get_result(l) :
temp_list = []
i = 0
while i < len(l) - 1 :
min = l[i]
while i<len(l)-1 and l[i][0] == l[i+1][0] :
if l[i][2] < l[i+1][2] :
min = l[i]
else :
min = l[i+1]
i += 1
temp_list.append(min)
i += 1
return temp_list
do,
print(get_result(l))
if the list is sorted, use this before invoking the method,
l.sort(key=lambda x: x[0])

Summing specific values in nested list Python [duplicate]

This question already has answers here:
Sum nested lists based on condition in Python
(6 answers)
nested lists combine values according to first value
(1 answer)
Closed 3 years ago.
I have a nested list that looks like this:
nested = [['a', 1], ['v', 2], ['a', 5], ['v', 3]]
I want to sum values in nested list for each letter value in list, so that output looks like this:
[['a', 6], ['v', 5]]
I have tried to play with for loops, but I couldnt find the solution.
There is probably a one liner for this using reduce and list comp, but I couldn't see it quickly.
nested = [['a', 1], ['v', 2], ['a', 5], ['v', 3]]
from collections import defaultdict
d = defaultdict(int)
for i in nested:
d[i[0]] += i[1]
retval = []
for k, v in d.items():
retval.append([k, v])
print(retval) # [['a', 6], ['v', 5]]

How to combine two list of lists to a new list [duplicate]

This question already has answers here:
How to get the cartesian product of multiple lists
(17 answers)
Closed 7 years ago.
I have a problem like this. I have two lists, A and B, where A=[[1,2],[3,4],[5,6]] and B=[["a","b"],["c","d"]], I would like to got a new list from these two like
C = [
[[1,2],["a","b"]],
[[3,4],["a","b"]],
[[1,2],["c","d"]],
[[3,4],["c","d"]]
]
I had try the following code:
A = [[1,2],[3,4]]
B=[["a","b"],["c","d"]]
for each in A:
for evey in B:
print each.append(evey)
However, the output is None.
Any helpful information are appreciated. Thank you.
By the way, I had try to replace the "append" with simple "+". The output is a list which elements are not list.
This was answered here: Get the cartesian product of a series of lists?
Try this:
import itertools
A = [[1,2],[3,4]]
B = [["a","b"],["c","d"]]
C = []
for element in itertools.product(A,B):
C.append(list(element))
print C
This is one way to do it:
A = [[1,2],[3,4]]
B=[["a","b"],["c","d"]]
C = zip(A,B)
The output here is a list of tuples:
[([[1, 2], [3, 4]],), ([['a', 'b'], ['c', 'd']],)]
If you want a list of lists, you can do this:
D = [list(i) for i in zip(A, B)]
The output:
[[[1, 2], ['a', 'b']], [[3, 4], ['c', 'd']]]
Try this. You have to append each couple of elements in each iteration.
result = []
for each in A:
for evey in B:
result.append([each,evey])
>>>result
[[[1, 2], ['a', 'b']],
[[1, 2], ['c', 'd']],
[[3, 4], ['a', 'b']],
[[3, 4], ['c', 'd']]]
OR
simply use itertools.product
>>>from itertools import product
>>>list(product(A,B))
[([1, 2], ['a', 'b']),
([1, 2], ['c', 'd']),
([3, 4], ['a', 'b']),
([3, 4], ['c', 'd'])]
You can use itertools.product to achieve this.
import itertools
list(itertools.product(A,B)) # gives the desired result
[([1, 2], ['a', 'b']),
([1, 2], ['c', 'd']),
([3, 4], ['a', 'b']),
([3, 4], ['c', 'd']),
([5, 6], ['a', 'b']),
([5, 6], ['c', 'd'])]
itertools.product(*iterables[, repeat])
It returns the Cartesian product of input iterables
Eg.
product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
Don't print return value of append(), try this:
A = [[1,2],[3,4]]
B=[["a","b"],["c","d"]]
C = []
for each in B:
for evey in A:
C.append([evey, each])
print C

Categories

Resources