Related
I have a very long list named CB with possibly repeated elements. For example, CB could be [[0, 0], [0, 1], [0, 2], [0, 1], [1, 1], [1, 2], [0, 2], [1, 2], [2, 2]]. Each element in CB is a list of sorted numbers.
In this example, I want to keep
[[0,0], [0,1], [0,2], [1,1], [1,2], [2,2]].
I've tried to use CB1=np.unique(CB), but it returns [0,1,2], which is not what I wanted.
I also tried to use CB1=list(set(CB)), but got the following error: TypeError: unhashable type: 'list'.
How to solve this problem? It would be great if you could solve it with the simplest possible code. A python function or one line of code would be awesome. Thanks!
If you use np.unique, you want to use the axis keyword argument:
data = [[0, 0], [0, 1], [0, 2], [0, 1], [1, 1], [1, 2], [0, 2], [1, 2], [2, 2]]
np.unique(data, axis=0)
array([[0, 0],
[0, 1],
[0, 2],
[1, 1],
[1, 2],
[2, 2]])
if you want to use set, you need to convert to hashable type, e.g. tuple:
data = map(tuple, data)
set(data)
{(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)}
if you need then converted back to the original list type, then the complete 1-liner would be:
data = list(map(list,set(map(tuple, data))))
I am trying to iterate through a 3-D list in python(not numpy but I am willing to convert to a numpy array if this makes it easier) in such a way that from a list like this:
a = [[[0, 0], [3, 0]], [[1, 0], [4, 0]], [[2, 0], [6, 0]] ]
I can get the output
[0,0]
[1,0]
[2,0]
[3,0]
[4,0]
[6,0]
I can't figure out how to make it iterate like this...
My code:
a = [[[0, 0], [0, 0]], [[1, 0], [0, 0]], [[2, 0], [0, 0]] ]
for i in range(len(a)):
for z in range(len(a[i])):
print(a[i][z])
I've tried different things but can't seem to get this output.
I think you want to print the nth sub-sublists consecutively from each sublist. You could unpack and zip a to get an iterable of tuples, then print each pair in them:
for tpl in zip(*a):
for pair in tpl:
print(pair)
Output:
[0, 0]
[1, 0]
[2, 0]
[3, 0]
[4, 0]
[6, 0]
Try:
print(*[i for v in zip(*a) for i in v], sep="\n")
Prints:
[0, 0]
[1, 0]
[2, 0]
[3, 0]
[4, 0]
[6, 0]
In case you want to just traverse the elements column wise, you can convert the list to numpy array, then stack the columns and print:
import numpy as np
a = [[[0, 0], [3, 0]], [[1, 0], [4, 0]], [[2, 0], [6, 0]] ]
arr = np.stack(np.array(a), axis=1)
for p in arr:
for x in p:
print(x)
The solution below is based on the previous assumption of printing each item in the sublist based on sorted order:
You can use itertools to flatten the 3d to 2d list and then sort the 2d list based on first element in each sublist. Then print the sorted list.
import itertools
a = [[[0, 0], [3, 0]],[[1, 0], [4, 0]],[[2, 0], [6, 0]]]
flat_list = list(itertools.chain(*a))
sorted_list = sorted(flat_list, key=lambda x: x[0])
for i in sorted_list:
print(i)
This is the correct way of iterating like you're trying to do:
a = [[[0, 0], [0, 0]], [[1, 0], [0, 0]], [[2, 0], [0, 0]] ]
for i in range(len(a)):
for z in range(len(a[i])):
print((a[i])[z])
If it is simpler for you, instead of iterating on the length of the lists with an index, try iterating on the elements of the lists:
a = [[[0, 0], [0, 0]], [[1, 0], [0, 0]], [[2, 0], [0, 0]] ]
for a1 in a:
for a2 in a1:
print(a2)
I have a list having sublists of numbers and want to extract specific ones. In my simplified example I have two main sublists and each one has its own pairs of numbers:
data=[[[1, 0], [2, 0], [2, 1], [2, 2],\
[1, 0], [1, 1], [1, 2],\
[0, 1], [0, 2], [0, 3]],\
[[1, 0], [2, 0],\
[1, 0],\
[0, 1], [0, 2], [1, 2],\
[1, 0], [1, 1], [1, 1]]]
Pairs stored in data can be divided based on some rules and I want the last pair of each division. For simplicity I have shown each division as a row in data. Each division starts with [1, 0] or [0, 1] and these two pairs are break points. Then, simply I want the last pair before each break points. In cases I may have no point between two break points and I only export the previous break point. Finally I want it as the following list:
data=[[[2, 2],\
[1, 2],\
[0, 3]],\
[[2, 0],\
[1, 0],\
[1, 2],\
[1, 1]]]
You can do the following, using enumerate:
def fun(lst):
return [p for i, p in enumerate(lst) if i==len(lst)-1 or set(lst[i+1])=={0,1}]
[*map(fun, data)]
# [[[2, 2], [1, 2], [0, 3]], [[2, 0], [1, 0], [1, 2], [1, 1]]]
fun filters a nested list for all elements that are either last or succeeded by [0, 1] or [1, 0].
data=[[[1, 0], [2, 0], [2, 1], [2, 2],
[1, 0], [1, 1], [1, 2],
[0, 1], [0, 2], [0, 3]],
[[1, 0], [2, 0],
[1, 0],
[0, 1], [0, 2], [1, 2],
[1, 0], [1, 1], [1, 1]]]
newData = []
for subarray in data:
new_subarray = []
for i,item in enumerate(subarray):
if item == [0,1] or item == [1,0]:
if i> 0:
new_subarray.append(subarray[i-1])
if i == len(subarray)-1:
new_subarray.append(item)
newData.append(new_subarray)
print(newData)
Here is a fun little unreadable numpy oneliner:
import numpy as np
[np.array(a)[np.roll(np.flatnonzero(np.logical_or(np.all(np.array(a)==(1, 0), axis=1), np.all(np.array(a)==(0, 1), axis=1)))-1, -1)].tolist() for a in data]
# [[[2, 2], [1, 2], [0, 3]], [[2, 0], [1, 0], [1, 2], [1, 1]]]
It works but in reality you'd better use schwobaseggl's solution.
So I have a list like below:
points = [[0, 0], [5, 3], [0, 5], [0, 2], [1, 3], [5, 3]]
I have been using
points.sort(key=lambda pair: pair[0])
to sort the list. But this only sorts it by first value without looking at the second value.
The result of this code is as below:
[[0, 0], [0, 5], [0, 2], [1, 3], [5, 3], [5, 3]]
However, I want to sort is such that the result is:
[[0, 0], [0, 2], [0, 5], [1, 3], [5, 3], [5, 3]]
How do I do it?
Also, while we are at it, how do i remove the duplicates from this list? The final result should be like:
[[0, 0], [0, 2], [0, 5], [1, 3], [5, 3]]
Python already sorts iterable containers (tuples, lists, ...) and strings lexicographically.
>>> points = [[0, 0], [5, 3], [0, 5], [0, 2], [1, 3], [5, 3]]
>>> sorted(points)
[[0, 0], [0, 2], [0, 5], [1, 3], [5, 3], [5, 3]]
import itertools
points = [[0, 0], [5, 3], [0, 5], [0, 2], [1, 3], [5, 3]]
points.sort()
nList = list(points for points,_ in itertools.groupby(points))
print nList
Result:
[[0, 0], [0, 2], [0, 5], [1, 3], [5, 3]]
You can have a sort key that first sorts by the first element x[0], and if their are ties, sort by the second element x[1]:
>>> points = [[0, 0], [5, 3], [0, 5], [0, 2], [1, 3], [5, 3], [0, 4]]
>>> sorted(points, key = lambda x: (x[0], x[1]))
[[0, 0], [0, 2], [0, 4], [0, 5], [1, 3], [5, 3], [5, 3]]
If you don't want any duplicates in this final list, then you can do this:
points = [[0, 0], [5, 3], [0, 5], [0, 2], [1, 3], [5, 3]]
sorted_lst = sorted(points, key = lambda x: (x[0], x[1]))
seen = set()
no_dups = []
for lst in sorted_lst:
curr = tuple(lst)
if curr not in seen:
no_dups.append(lst)
seen.add(curr)
print(no_dups)
# [[0, 0], [0, 2], [0, 5], [1, 3], [5, 3]]
Which has a set seen which keeps track of what sublists have been added, and a list no_dups where the lists get added. If an element is not in seen and add it to the final list, and add it to seen, which indicates that the element has already been added.
Also since type list is not a hashable type, you cannot add them directly to a set. In the above code, the lists are converted to tuples and added to seen, which is a hashable type.
Try itemgetter
from operator import itemgetter
sorted(points, key=itemgetter(0, 1))
I have this nested list:
nested = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
I wanted to subtract 1 from the first 2 elements of the inner list so I tried it with list comprehension:
nested = [[x - 1 for x in stack[0:2]] for stack in nested]
It did give me back the first 2 elements subtracted by 1 for the inner lists but it removed the last element completely
nested = [[0, 0], [1, 1], [2, 2]]
I thought that by slicing the list, it will not affect the other element. However in this case it didn't work. Can someone explain this to me?
To keep the 3rd element, include it in the list comprehension:
>>> [ [x - 1 for x in stack[0:2]] + stack[2:] for stack in nested ]
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
The above works for stack of any length.
Or, if stack always has exactly three elements:
>>> [[x-1, y-1, z] for x, y, z in nested]
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
Or, you can make the changes in place:
>>> for stack in nested: stack[0]-=1; stack[1]-=1
...
>>> nested
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
Another option is to use numpy which does this sort of slicing naturally
import numpy as np
nested = np.array([[1, 1, 1], [2, 2, 2], [3, 3, 3]])
nested[:,:2] -= 1
returns
array([[0, 0, 1],
[1, 1, 2],
[2, 2, 3]])
Try it like this:
nested = [[x - 1 if i < 2 else x for i,x in enumerate(stack)] for stack in nested]
This will affect only first two elements keeping the rest as is.
You can use enumerate:
nested = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_nested = [[a-1 if i == 0 or i == 1 else a for i, a in enumerate(b)] for b in nested]
Output:
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]
Edit: alternative, with map:
nested = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
new_nested = [map(lambda x:x-1, i[:2])+[i[-1]] for i in nested]
Output:
[[0, 0, 1], [1, 1, 2], [2, 2, 3]]