How to compare elements in list-of-lists? - python

I have a list which contains list of elements(the number of elements in each inner list are not same) and I want to group all the elements in same index into separate groups and return maximum values in each group:
for example,
elements = [[89, 213, 317], [106, 191, 314], [87]]
I want to group these elements like this,
groups = [[89,106,87],[213,191],[317,314]]
the expected result is the maximum values of each list in groups : 106 ,213 and 317
I tried to group elements using following code:
w = zip(*elements)
result_list = list(w)
print(result_list)
output I got is
[(89, 106, 87)]

You can use itertools.zip_longest with fillvalue=float("-inf"):
from itertools import zip_longest
elements = [[89, 213, 317], [106, 191, 314], [87]]
out = [max(t) for t in zip_longest(*elements, fillvalue=float("-inf"))]
print(out)
Prints:
[106, 213, 317]
NOTE: zip() won't work here, because (as you stated) the number of elements in each inner list are not same. With zip_longest() the missing elements are substituted with fillvalue, in this case -infinity (and -infinity will be always the lowest value in the max() function)

Try creating a dictionary keyed with the index of each sub list, then turning the values into the new list, then map to max:
from collections import defaultdict
elements = [[89, 213, 317], [106, 191, 314], [87]]
i_d = defaultdict(list)
for sub in elements:
for i, v in enumerate(sub):
i_d[i].append(v)
maxes = list(map(max, i_d.values()))
print(maxes)
i_d:
defaultdict(<class 'list'>, {0: [89, 106, 87], 1: [213, 191], 2: [317, 314]})
maxes:
[106, 213, 317]

Related

strange output when returning the argument list [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 3 years ago.
Code
def removeEven(List):
for x in List:
if x % 2 == 0:
List.remove(x)
return List
print(removeEven([18, 106, -158, -124, 199, -28, -68, -91, 46, -190, 63, -30, 142, -36, -162, -121, 14, -192, -143, -57, -59, -129, -146, -76, -186, -84, 70, 19, -13, -12, -5, 179, -191, -43, 160, -156, 105, 104, 93, -188, -184, -197, -136, -35, 16]))
Output
[106, -124, 199, -68, -91, -190, 63, 142, -162, -121, -192, -143, -57, -59, -129, -76, -84, 19, -13, -5, 179, -191, -43, -156, 105, 93, -184, -197, -35]
Code
def removeEven(List):
result = []
for x in List:
if x % 2 != 0:
result.append(x)
return result
Output
[199, -91, 63, -121, -143, -57, -59, -129, 19, -13, -5, 179, -191, -43, 105, 93, -197, -35]
I came across this strange behavior. I am writing a simple function to remove even numbers from a list but when I modify the list that is passed as an argument and return it I get a weird output. Does anyone know what the reason is?
Please note i am not looking for answer to this problem it is easy to google but just explanation about why the output is different when i don't create a new list and return it.
One Liner in Python using list comprehension:
[x for x in li if x % 2 != 0]
strange output when returning the argument list
You are not permitted to remove elements from the list while iterating over it using a for loop. The best way to do this involves making a new list - either iterate over a copy, or construct a list with only the elements you want and assign it back to the same variable.
As we know, every item in a list lives at its own unique index; which are in order, starting from 0. If we remove an item, any item with an index greater than the one we've removed has now been shifted down.
And here's why that matters:
foo = ['a', 'b', 'c', 'd']
for index in range(len(foo)):
del foo[index]
In this loop, we're removing all the elements, so we should end up with foo == [], right? This is not the case. In our first trip through the loop, we remove the item at index 0, and the item at index 1 becomes the item at index 0. Our next time through the loop, we remove the item at index 1 which was previously the item at index 2.
See this to learn more on How to remove elements while iterating over a list. See this to learn more on How to remove elements while reverse iterating a list.

How to append two-dimensional python list without for loop?

Let's suppose that I have 3 python two-dimensional lists (data_1, data_2, data_3) of 10x5 dimensions. I want to make one list (all_data) from them with 30x5 dimensions. For now, I am doing this by applying the following:
data_1 = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], ..., [46, 47, 48, 49, 50]]
data_2 = [[101, 102, 103, 104, 105], [106, 107, 108, 109, 110], ..., [146, 147, 148, 149, 150]]
data_3 = [[201, 202, 203, 204, 205], [206, 207, 208, 209, 210], ..., [246, 247, 248, 249, 250]]
all_data = []
for index, item in enumerate(data_1):
all_data.append(item)
for index, item in enumerate(data_2):
all_data.append(item)
for index, item in enumerate(data_3):
all_data.append(item)
If I simply do something like this:
all_data.append(data_1)
all_data.append(data_2)
all_data.append(data_3)
then I get a list of 3x10x5 which is not what I want.
So can I create a 30x5 list by appending three 10x5 lists without using any for loop?
You can just extend your list.
data = []
data.extend(d1)
data.extend(d2)
data.extend(d3)
Simply write:
all_data = data_1 + data_2 + data_3
If you want to merge all the corresponding sublists of these lists, you can write:
# function that merges all sublists in single list
def flatten(l):
return [el for subl in l for el in subl]
# zipped - is a list of tuples of corresponding items (our deep sublists) of all the lists
zipped = zip(data_1, data_3, data_3)
# merge tuples to get single list of rearranges sublists
all_data = flatten(zipped)
How about:
all_data = data_1 + data_2 + data_3
This should work:
data=[]
data[len(data):] = data1
data[len(data):] = data2
data[len(data):] = data3
In case you don't mind it being lazy, you could also do
import itertools
all_data = itertools.chain(data1, data2, data3)

appending list of numbers to new list python

This is kind of hard to describe so I'll show it mainly in code. I'm taking a List of a List of numbers and appending it to a masterList.
The first list in master list would be the first element of each list. I would insert 0 in it's appropriate index in the master list. Then I would move on to the next list. I would choose the first element of the 2nd list and append it to the second list in the master list, since it's index would be 1, I would insert 0 to the first index of that list. This is WAY confusing, please comment back if you have any questions about it. I'll answer back fast. This is really bugging me.
ex:
L = [[], [346], [113, 240], [2974, 1520, 684], [169, 1867, 41, 5795]]
What i want is this:
[[0,346,113,2974,169],[346,0,240,1520,1867],[113,240,0,684,41],[2974,1520,684,0,5795],[169,1867,41,5795,0]]
IIUC, you want something like
>>> L = [[], [346], [113, 240], [2974, 1520, 684], [169, 1867, 41, 5795]]
>>> [x+[0]+[L[j][i] for j in range(i+1, len(L))] for i, x in enumerate(L)]
[[0, 346, 113, 2974, 169], [346, 0, 240, 1520, 1867],
[113, 240, 0, 684, 41], [2974, 1520, 684, 0, 5795],
[169, 1867, 41, 5795, 0]]
which might be easier to read in expanded form:
combined = []
for i, x in enumerate(L):
newlist = x + [0]
for j in range(i+1, len(L)):
newlist.append(L[j][i])
combined.append(newlist)

Python: List appending issue

I am having a logical error of sorts and I can not seem to pick it out. Here is what I have:
Document = 'Sample1'
locationslist = []
thedictionary = []
userword = ['the', 'a']
filename = 'Sample1'
for inneritem in userword:
thedictionary.append((inneritem,locationslist))
for position, item in enumerate(file_contents):
if item == inneritem:
locationslist.append(position)
wordlist = (thedictionary, Document)
print wordlist
So basically I am trying to create a larger list (thedictionary) from a smaller list (locationslist) together with the particular userword. I almost have it except I have that the output is putting all the locations of all the words (in which there are only 2 - 'the' and 'a') in each of the lists. Seems like there is a simple logic problem - but I can't seem to spot it. The output is:
([('the', [5, 28, 41, 97, 107, 113, 120, 138, 141, 161, 2, 49, 57, 131, 167, 189, 194, 207, 215, 224]),
('a', [5, 28, 41, 97, 107, 113, 120, 138, 141, 161, 2, 49, 57, 131, 167, 189, 194, 207, 215, 224])],
'Sample1')
But should be:
([('the', [5, 28, 41, 97, 107, 113, 120, 138, 141, 161]),
('a', [2, 49, 57, 131, 167, 189, 194, 207, 215, 224])],
'Sample1')
See how both position lists are being appended to each of the problematic output concerning each of the userwords 'the' and 'a'? I could use advice on what I am doing wrong here..
You only create one locationslist, so you only have one. It is shared by both words. You need to create a new locationslist on each loop iteration:
for inneritem in userword:
locationslist = []
thedictionary.append((inneritem,locationslist))
# etc.
You have only created the one locationslist, so all of the locationslist.append() calls modify that list. You append the same locationslist to as many tuples in thedictionary as you have elements in userword. You should create one location list for each element of userword.
The algorithm you have could be written as a nested set of list comprehensions, which would lead to the correct lists being created:
user_word = ['the', 'a']
word_list = ([(uw,
[position for position, item in enumerate(file_contents)
if item == uw])
for uw in user_word],
'Sample1')
That would still call enumerate(file_contents) once for each item in user_word, which could be expensive if file_contents is large.
I suggest you rewrite this to pass over file_contents once, check the item at each position against the contents of user_word, and append the position to only the list for the particular user_word found at that position. I would suggest using a dictionary to keep the user_word lists separate and accessible:
document = 'Sample1'
temp_dict = dict((uw, []) for uw in user_word)
for position, item in enumerate(file_contents):
if item in temp_dict:
temp_dict[item].append(position)
wordlist = ([(uw, temp_dict[uw]) for uw in user_word], document)
Either solution will get you the positions of each user_word, in order of appearance, in the document being scanned. It will also return the list structure you're looking for.

python - get item number from list

I just asked the following question:
Python - find integer closest to 0 in list
The best answer was to use: min(lst, key=abs).
That code returns the item from the list.
How do I get the item number from the list? (i.e. 2 instead of -18)
You'd need to augment your list with indices:
min(enumerate(lst), key=lambda x: abs(x[1]))
It'll return the index and closest-to-zero value, use [0] if you only need the index.
On your example:
>>> example = [237, 72, -18, 237, 236, 237, 60, -158, -273, -78, 492, 243]
>>> min(enumerate(example), key=lambda x: abs(x[1]))
(2, -18)
>>> min(enumerate(example), key=lambda x: abs(x[1]))[0]
2
This is very efficient (worst-case O(n)); you can use example.index(min(example, key=abs)) as well, but that has to go through the list twice in the worst case (O(2n)).
>>> lst = [237, 72, -18, 237, 236, 237, 60, -158, -273, -78, 492, 243]
>>> lst.index(min(lst, key=abs))
2
Try:
lst.index(min(lst, key=abs))
One way is after finding the integer you want to find, you can use "index"...
result = min(lst, key=abs)
index = lst.index(result)
print(index) # prints 2

Categories

Resources