I have the following list in Python:
[[1, 2], [3, 4], [4, 6], [2, 7], [3, 9]]
I want to group them into [[1,2,7],[3,4,6,9]]
My code to do this looks like this:
l=[[1, 2], [3, 4], [4, 6], [2, 7], [3, 9]]
lf=[]
for li in l:
for lfi in lf:
if lfi.intersection(set(li)):
lfi=lfi.union(set(li))
break
else:
lf.append(set(li))
lf is my final list. I do a loop over l and lf and when I find an intersection between an element from l and another from lf, I would like to merge them (union)
But I can't figure out why this is not working. The first to elements of the list l are being inserted with the append command, but the union is not working.
My final list lf looks like [set([1, 2]), set([3, 4])]
It seems to be something pretty basic, but I'm not familiar with sets.
I appreciate any help
Thanks
The problem is here:
lfi=lfi.union(set(li))
You are not modifying the set. You are creating a new set which is then discarded. The original set is still in the lf array. Use update instead:
lfi.update(li)
This modifies the original set instead of creating a new one. The result after making this change:
[set([1, 2, 7]), set([9, 3, 4, 6])]
Here is another way to write the same thing
For sets,
& means intersection
|= means update
I have also used map(set,l) so that you are not recreating the same set over and over
l=[[1, 2], [3, 4], [4, 6], [2, 7], [3, 9]]
lf=[]
for li in map(set,l):
for lfi in lf:
if lfi & li:
lfi |= li
break
else:
lf.append(li)
l=[[1, 2], [3, 4], [4, 6], [2, 7], [3, 9]]
lf=[]
for li in l:
for i, lfi in enumerate(lf):
if lfi.intersection(set(li)):
lfi=lfi.union(set(li))
lf[i] = lfi #You forgot to update the list
break
else:
lf.append(set(li))
Related
I have a series of lists, and I want to combine them in a larger nested list. However, I want to order them in a certain way. I want the first sub-list to be the one whose first element is zero. Then i want the second sub-list to be the one whose first element is the same as the LAST element of the previous list.
For example, here's four sub-lists;
[0, 3], [7, 0], [3, 8], [8, 7]
I want to end up with this;
[[0, 3], [3, 8], [8, 7], [7,0]]
I can't for the life of me see the code logic in my head that would achieve this for me.
Can anyone help please?
UPDATE
Solved!
Many thanks to all who contributed!
I think of your list as being a collection of links which are to be arranged into a chain. Here is an approach which uses #quanrama 's idea of a dictionary keyed by the first element of that link:
links = [[0, 3], [7, 0], [3, 8], [8, 7]]
d = {link[0]:link for link in links}
chain = []
i = min(d)
while d:
link = d[i]
chain.append(link)
del d[i]
i = link[1]
print(chain) #[[0, 3], [3, 8], [8, 7], [7, 0]]
Another approach with a generator function:
links = [[0, 3], [7, 0], [3, 8], [8, 7]]
def get_path(links, *, start=0, end=0):
linkmap = dict(links)
key = start
while True:
link = linkmap[key]
yield [key,link]
key = link
if link == end:
break
print(list(get_path(links)))
print(list(get_path(links,start=3,end=3)))
# [[0, 3], [3, 8], [8, 7], [7, 0]]
# [[3, 8], [8, 7], [7, 0], [0, 3]]
You can try something like this:
source = [[0, 3], [7, 0], [3, 8], [8, 7]]
# Start at 0
last_val = 0
# this will be the output
l = []
while len(l)==0 or last_val!=0:
# Find the first value where the first element is last_val
l.append(next(i for i in source if i[0]==last_val))
# set last val to the second element of the list
last_val = l[-1][1]
print(l)
I have a 2D list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]], and I want to delete columns in a loop.
For example, columns with index: 0(first) and 2(last) - - the result after deletions should be: [8, 5, 5].
There is a problem, because when I delete the 0th column, the size of the list is decreased to (0,1), and the 2nd index is out of scope.
What is the fastest method to delete columns in a loop without the out-of-scope problem?
For a better picture:
[[1, 8, 3],
[4, 5, 6],
[0, 5, 7]]
There is no such shortcut in python except for iterating over all the list items and removing those index values.
However, you can use pandas which is meant for some other purpose but will do the task.
import pandas as pd
s = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
df = pd.DataFrame(s,columns=['val1','val2','val3'])
li = df.drop('val1',axis=1).values.tolist()
now li will look like this
[[8, 3], [5, 6], [5, 7]]
You can use numpy like this:
import numpy as np
my_list = np.array([[1, 8, 3], [4, 5, 6], [0, 5, 7]])
new_list = my_list[:, 1].copy()
print(new_list)
Output:
>>> [8, 5, 5]
Also numpy.delete(your_list, index, axis) is do the same job:
new_list = np.delete(my_list,(0, 2), axis=1)
(0, 2) is the indices of the columns 0 and 2
axis=1 says numpy that (0, 2) are columns indices not rows.
if you want to delete rows 0 and 2 you can change axis=1 to axis=0
Output is a little different:
>>> array([[8],
[5],
[5]])
For a pure python approach:
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
new_list = [value[1] for value in my_list]
print(new_list)
Output:
>>> [8, 5, 5]
L is 2D list:
print(map(lambda x: x[1:], L))
data= [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
index_to_remove=[0,2]
[list(x) for x in zip(*[d for i,d in enumerate(zip(*data)) if i not in index_to_remove])]
If I understood your question correctly, you want to keep the middle element (index 1) of each list,in that case I would suggest creating a new list. There could be other better ways, for sure. But you could try this, if this works for you:
twoD_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
def keep_col( twoD_list ,index_to_keep = 1):
final_list = []
for x in twoD_list:
final_list.append(x[index_to_keep])
return final_list
final_list = keep_col( twoD_list , 1)
Final output:
[8,5,5]
Assuming you always want only the second element and the inner lists always have at least two elements.
Pure python with list comprehension:
lst = [
[1, 8, 3],
[4, 5, 6],
[0, 5, 7],
]
filtered_lst = [
inner_element
for inner_lst in lst
for i, inner_element in enumerate(inner_lst)
if i == 1
]
print(filtered_lst)
# [8, 5, 5]
If you want you can the reassign the new list to the old variable:
lst = filtered_lst
The advantages of this method are:
no need to worry about the list being altered while you iterate it,
no need to import other libraries
list comprehension is built-in
list comprehension is often the fastest way to filter a list (see for example this article)
easier to read and maintain that other solutions (in my opinion).
Via itemgetter to extract the value at index 1.
from operator import itemgetter
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
result = list(map(itemgetter(1), my_list))
try this
my_list = [[1, 8, 3], [4, 5, 6], [0, 5, 7]]
filter_col=[0,2]
col_length=3
my_list=[[x[i] for i in range(col_length) if i not in filter_col] for x in my_list]
u do not want to directly mutate the list that you are working on
this performs a list comprehension to create a new list from the existing list
edit:
just saw u wanted only a flat list
assuming u only want one element for the list u can use
my_list=[x[1] for x in my_list]
Given this value:
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
is there a way to use a list comprehension to produce this value:
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]?
I'd prefer to do it without using zip, if possible.
Thanks!
Edit: My reason for not wanting to use zip was that I used zip to do something similar before (albeit not a list of lists), and it was recommended that I try a list comprehension instead, which made it a little neater. I thought the same principle might apply here, but maybe not, since this is a list of lists and not just a single list like the previous problem.
Also, my attempts at this before posting this question were not even worth sharing. It was basically a list comprehension that created a single list, and I couldn't figure out how to create a list of lists with it. Maybe it's not as simple as I had hoped. I might go with zip after all.
Try this:
list1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Using zip you can take values from inner lists together and using * you can unpack these values
[*zip(*list1)]
or
list(map(list,zip(*list1)))
Without zip:
>>> [*map(lambda *a: [*a], *a)]
[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Without zip:
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
output = [[a[0][i],a[1][i],1[2][i]] for i in range(0,len(a))]
How about this?
original = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
result = []
for x in range(len(min(orig))):
result.append([item[x] for item in orig])
Based on my testing, this works just like #Himanshu's method of doing [*zip(*list1)] and list(map(list,zip(*list1)))
When given a list of lists like: [[5, 2] [2, 5]]
I want to reduce this list to this: [[5, 2]] or [[2, 5]]
I've already tried the following: list(map(list, set(map(frozenset, parts_to_add))))
But the problem with this method is that it turns my lists in sets and while this works - it filters out all the equivalent lists - it also eats all of my duplicate values; When given [[3, 3]] it returns [[3]], due to the nature of sets in python. Is there another way of doing this?
Any help would be grately appreciated.
You could do :
data = [[5, 2], [2, 5], [3, 3]]
result = set(tuple(e) for e in map(sorted, data))
print([list(e) for e in result])
Output
[[2, 5], [3, 3]]
As #soon mentioned you could use a frozen Counter, for example:
from collections import Counter
data = [[5, 2], [2, 5], [3, 3]]
result = [e for e in {frozenset(Counter(e)): e for e in data}.values()]
print(result)
Output
[[2, 5], [3, 3]]
The above approach also uses a dict for removing duplicates instead of a set.
A more straightforward approach would be,
data = [[2, 5], [5, 2], [3, 6], [2, 5], [6, 3]]
result = []
for i in range(len(data)):
data[i].sort()
if data[i] not in result:
result.append(data[i])
In [49]: result
Out[49]: [[2, 5], [3, 6]]
I'm very new to python (using python3) and I'm trying to add numbers from one list to another list. The only problem is that the second list is a list of lists. For example:
[[1, 2, 3], [4, 5, 6]]
What I want is to, say, add 1 to each item in the first list and 2 to each item in the second, returning something like this:
[[2, 3, 4], [6, 7, 8]]
I tried this:
original_lst = [[1, 2, 3], [4, 5, 6]]
trasposition_lst = [1, 2]
new_lst = [x+y for x,y in zip(original_lst, transposition_ls)]
print(new_lst)
When I do this, I get an error
can only concatenate list (not "int") to list
This leads me to believe that I can't operate in this way on the lists as long as they are nested within another list. I want to do this operation without flattening the nested list. Is there a solution?
One approach using enumerate
Demo:
l = [[1, 2, 3], [4, 5, 6]]
print( [[j+i for j in v] for i,v in enumerate(l, 1)] )
Output:
[[2, 3, 4], [6, 7, 8]]
You can use enumerate:
l = [[1, 2, 3], [4, 5, 6]]
new_l = [[c+i for c in a] for i, a in enumerate(l, 1)]
Output:
[[2, 3, 4], [6, 7, 8]]
Why don't use numpy instead?
import numpy as np
mat = np.array([[1, 2, 3], [4, 5, 6]])
mul = np.array([1,2])
m = np.ones(mat.shape)
res = (m.T *mul).T + mat
You were very close with you original method. Just fell one step short.
Small addition
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
new_lst = [[xx + y for xx in x] for x, y in zip(original_lst, transposition_lst)]
print(new_lst)
Output
[[2, 3, 4], [6, 7, 8]]
Reasoning
If you print your original zip it is easy to see the issue. Your original zip yielded this:
In:
original_lst = [[1, 2, 3], [4, 5, 6]]
transposition_lst = [1, 2]
for x,y in zip(original_lst, transposition_lst):
print(x, y)
Output
[1, 2, 3] 1
[4, 5, 6] 2
Now it is easy to see that you are trying to add an integer to a list (hence the error). Which python doesn't understand. if they were both integers it would add them or if they were both lists it would combine them.
To fix this you need to do one extra step with your code to add the integer to each value in the list. Hence the addition of the extra list comprehension in the solution above.
A different approach than numpy that could work even for lists of different lengths is
lst = [[1, 2, 3], [4, 5, 6, 7]]
c = [1, 2]
res = [[l + c[i] for l in lst[i]] for i in range(len(c))]