Iterate through list in nested list - Python - python

I have a long list with nested lists with each list consisting of multiple xy-coordinates.
In short, my lists looks like this
MyList = [ [ [1, 2], [1, 2] ], [ [1, 2], [1, 2] ], [ [1, 2], [1, 2] ]...]]]
I would like to extract all the "1's" to one variable, and all the "2's" to one variable.
So extract first element to a new list, and extract second element to another new list.
I have tried
for list in MyList:
for newList in list:
number1 = [item[0] for item in newList]
number2 = [item[1] for item in newList]
Which gave me the error "int object is not subscriptable".
I also tried
def Extract(MyList):
return list(list(zip(*MyList))[0])
Lastly I tried to just print the "1's" out to see if it would work
print(MyList[:][:][0])
output: [[1, 2], [1, 2]]

Try this:
flatlist = [el for lst1 in MyList for lst2 in lst1 for el in lst2]
number1, number2 = flatlist[0::2], flatlist[1::2]
First you flat the list, and then you split it into two lists with alternating elements.

I would do it like so:
>>> a = MyList
>>> x = [a[i][j][0] for i in range(len(a)) for j in range(len(a[i]))]
>>> x
[1, 1, 1, 1, 1, 1]
>>> y = [a[i][j][1] for i in range(len(a)) for j in range(len(a[i]))]
>>> y
[2, 2, 2, 2, 2, 2]
You're basically iterating over each tuple of coordinates and take the X coordinate ([0]), respectively the y coordinate ([1]).
There might be better ways, this is the quick one I came up with.

Simply you can handle this with three for loop if time complexity is not an issue:
one = []
two = []
for item in MyList:
for arr in item:
for num in arr:
if num == 1:
one.append(num)
else:
two.append(num)
# [1, 1, 1, 1, 1, 1]
# [2, 2, 2, 2, 2, 2]

Related

Permutations between 2 lists

From 2 list i would like to know an optimal way in Python to do a sort of "indexed permutation".
This is how this would look like :
input :
list2 = [3,4,5]
list1 = [0,1,2]
output
[[0,1,2], [0,1,5], [0,4,2], [3,1,2],
[3,4,5], [3,4,2], [3,1,5], [0,4,5],
]
So each element of the lists remains in the same index.
You basically want two variables: list_to_pick, which can vary in range(number_of_lists), and index_to_swap which can vary in the range(-1, len(list1)). Then, you want the product of these two ranges to decide which list to pick, and which item to swap. When index_to_swap is -1, we won't swap any items
import itertools
source = [list1, list2]
result = []
for list_to_pick, index_to_swap in itertools.product(range(len(source)), range(-1, len(source[0])):
# Make a copy so we don't mess up the original list
selected_list = source[list_to_pick].copy()
# There are only two lists, so the other list is at index abs(list_to_pick - 1)
other_list = source[abs(list_to_pick - 1)]
# We swap only if index_to_swap >= 0
if index_to_swap >= 0:
selected_list[index_to_swap] = other_list[index_to_swap]
result.append(selected_list)
Which gives:
[[0, 1, 2],
[3, 1, 2],
[0, 4, 2],
[0, 1, 5],
[3, 4, 5],
[0, 4, 5],
[3, 1, 5],
[3, 4, 2]]
The order is not the same as your required list, but all the "permutations" are there. If you want the same order as in your question, you will have to define the second argument to itertools.product as:
swap_indices = [-1] + list(range(len(source[0])-1, -2, -1))

Python - Check how many times a list of numbers is included in a list of lists of numbers

thank you for helping out
So, I have a list of lists of numbers
list1 = [
[1, 2, 3, 4],
[1, 2, 3],
[1, 2, 4]
]
Now, I want to check how many times this list:
list2 = [3,1,2]
is included in the list1
For this example the output should be:
2
I also tried this:
list1 = [
[1, 2, 3, 4, 5],
[1, 2, 4],
[1, 2, 3, 4],
]
def removeElements(A, B):
for i in range(len(B)-len(A)+1):
for j in range(len(A)):
if B[i + j] != A[j]:
break
else:
return True
return False
s2 = [1,2]
count = sum(removeElements(sorted(s2), sorted(lst)) for lst in list1)
print(count)
But it doesn't work if s2 = [1,4] as it's checking the numbers in order
If you have an idea or a solution of how that can be achieved, please let me know
You can use sum with a generator expression to count, and sorted to compare lists regardless of order:
s2 = sorted(list2)
count = sum(s2 == sorted(lst) for lst in list1)
Or if you are a functional guy and into one-liners:
count = sum(map(sorted(list2).__eq__, map(sorted, list1)))
One should remark that this works so neatly because bool is a subclass of int, and boolean expressions can be summed like integers 0 and 1.
Update:
Since you clarified your problem and want to count the supersets (or superlists if there are duplicates), you can use Counter subtraction along the same lines:
from collections import Counter
c2 = Counter(list2)
count = sum(not (c2-Counter(lst)) for lst in list1)
list1 = [
[1, 2, 3],
[1, 2, 3],
[1, 2, 4]
]
'''We need to arrange elements in the lists in a one particular way,
since [3,1,2] and [1,2,3] are different.
Hence, sorting all the lists'''
list2 = sorted([3,1,2])
c=0 #Counter variable
for lst in list1: #Traversing through list1
lst=sorted(lst)
#From here on, comparing, if there is a list that is equal to list2
if len(lst)==len(list2):
flag=0
for i in range(len(lst)):
if lst[i]!=list2[i]:
flag=1
break
if flag==0:
c+=1
print(c)
Your problem logic deals with sets, not lists -- the ordering is immaterial. Convert everything to a set and simply count:
set_list = [set(elem) for elem in list1]
Now for your target list, simply check how many times it appears:
set_list.count(set(target))
list1 = [
[1, 2, 3],
[1, 2, 3],
[1, 2, 4],
]
check_list = [3, 5, 2]
count = 0
for l in list1:
temp = False
if sorted(check_list) == sorted(l):
temp = True
if temp:
count += 1
print(count)

Split a list into sub lists of decreasing size

Suppose I have a list as
list = [0,1,2,3]
How would I split the lists into something like
new_list = [[0,1,2,3],[1,2,3],[2,3],[3]]
I've tried using:
def change(list):
new_list = []
for i in range(len(list)):
total += [list:]
return new_list
but I get a return value of
new_list = [0,1,2,3,1,2,3,2,3,3]
Help would be greatly appreciated,
thanks.
Use a simple list comprehension, which iterates over the length of original list. Also, I have used variable name lst, since list is a python type.
Here you go:
>>> lst = [0,1,2,3]
>>> [lst[i:] for i in range(len(lst))]
[[0, 1, 2, 3], [1, 2, 3], [2, 3], [3]]
newlist=[]
list = [0,1,2,3]
i=0
while i<len(list):
newlist.append(list[i:])
i=i+1
print newlist
You can also use map with lambda
In [14]: map(lambda x: list[x:], xrange(len(list)))
Out[14]: [[0, 1, 2, 3], [1, 2, 3], [2, 3], [3]]
See this
from itertools import islice
# Input list
List1 = [1,2,3,4,5,6,7,8,9,10,11]
# [1,2,3,4],[5,6,7],[8,9],[10],[11]
length_to_split = [4, 3, 2, 1, 1]
# Using islice
X = iter(List1)
sublists = [list(islice(X, elem)) for elem in length_to_split]
print("Sublists : ", sublists)
output :
Sublists : [[1, 2, 3, 4], [5, 6, 7], [8, 9], [10], [11]]
Reference: https://docs.python.org/3/library/itertools.html

Merge two lists based on condition

I am trying to merge two lists based on position of index, so sort of a proximity intersection.
A set doesn't work in this case. What i am trying to do is match index in each list then if the element is one less than that of the element in other list, only then i collect it.
An example will explain my scenario better.
Sample Input:
print merge_list([[0, 1, 3], [1, 2], [4, 1, 3, 5]],
[[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])
Sample Output:
[[0,2],[4,6]]
so on position 0 in list1 we have 1, 3 and in list2 we have 2, 6. Since 1 is one less than 2, so we collect that and move on, now 3 is less than 6 but it's not one less than i.e. not 5 so we ignore that. Next we have [1, 2][1, 4], so both index/position 1, but 2 is not one less than 4 so we ignore that. Next we have [2, 2] in list2 both index 2 doesn't match any index in first list so no comparison. Finally we have [4, 1, 3, 5] [4, 1, 6] comparison. Both index match and only 5 in list one is one less than list two so we collect six hence we collect [4,6] meaning index 4 and match etc.
I have tried to make it work, but i don't seem to make it work.
This is my code so far.
def merge_list(my_list1, my_list2):
merged_list = []
bigger_list = []
smaller_list = []
temp_outer_index = 0
temp_inner_index = 0
if(len(my_list1) > len(my_list2)):
bigger_list = my_list1
smaller_list = my_list2
elif(len(my_list2) > len(my_list1)):
bigger_list = my_list2
smaller_list = my_list1
else:
bigger_list = my_list1
smaller_list = my_list2
for i, sublist in enumerate(bigger_list):
for index1 , val in enumerate(sublist):
for k, sublist2 in enumerate(smaller_list):
for index2, val2 in enumerate(sublist2):
temp_outer_index = index1 + 1
temp_inner_index = index2 + 1
if(temp_inner_index < len(sublist2) and temp_outer_index < len(sublist)):
# print "temp_outer:%s , temp_inner:%s, sublist[temp_outer]:%s, sublist2[temp_inner_index]:%s" % (temp_outer_index, temp_inner_index, sublist[temp_outer_index], sublist2[temp_inner_index])
if(sublist2[temp_inner_index] < sublist[temp_outer_index]):
merged_list.append(sublist[temp_outer_index])
break
return merged_list
No clue what you are doing, but this should work.
First, convert the list of lists to a mapping of indices to set of digits contained in that list:
def convert_list(l):
return dict((sublist[0], set(sublist[1:])) for sublist in l)
This will make the lists a lot easier to work with:
>>> convert_list([[0, 1, 3], [1, 2], [4, 1, 3, 5]])
{0: set([1, 3]), 1: set([2]), 4: set([1, 3, 5])}
>>> convert_list([[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])
{0: set([2, 6]), 1: set([4]), 2: set([2]), 4: set([1, 6])}
Now the merge_lists function can be written as such:
def merge_lists(l1, l2):
result = []
d1 = convert_list(l1)
d2 = convert_list(l2)
for index, l2_nums in d2.items():
if index not in d1:
#no matching index
continue
l1_nums = d1[index]
sub_nums = [l2_num for l2_num in l2_nums if l2_num - 1 in l1_nums]
if sub_nums:
result.append([index] + sorted(list(sub_nums)))
return result
Works for your test case:
>>> print merge_lists([[0, 1, 3], [1, 2], [4, 1, 3, 5]],
[[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])
[[0, 2], [4, 6]]
I believe this does what you want it to do:
import itertools
def to_dict(lst):
dct = {sub[0]: sub[1:] for sub in lst}
return dct
def merge_dicts(a, b):
result = []
overlapping_keys = set.intersection(set(a.keys()), set(b.keys()))
for key in overlapping_keys:
temp = [key] # initialize sublist with index
for i, j in itertools.product(a[key], b[key]):
if i == j - 1:
temp.append(j)
if len(temp) > 1: # if the sublist has anything besides the index
result.append(temp)
return result
dict1 = to_dict([[0, 1, 3], [1, 2], [4, 1, 3, 5]])
dict2 = to_dict([[0, 2, 6], [1, 4], [2, 2], [4, 1, 6]])
result = merge_dicts(dict1, dict2)
print(result)
Result:
[[0, 2], [4, 6]]
First, we convert your lists to dicts because they're easier to work with (this separates the key out from the other values). Then, we look for the keys that exist in both dicts (in the example, this is 0, 1, 4) and look at all pairs of values between the two dicts for each key (in the example, 1,2; 1,6; 3,2; 3,6; 2,4; 1,1; 1,6; 3,1; 3,6; 5,1; 5,6). Whenever the first element of a pair is one less than the second element, we add the second element to our temp list. If the temp list ends up containing anything besides the key (i.e. is longer than 1), we add it to the result list, which we eventually return.
(It just occurred to me that this has pretty bad performance characteristics - quadratic in the length of the sublists - so you might want to use Claudiu's answer instead if your sublists are going to be long. If they're going to be short, though, I think the cost of initializing a set is large enough that my solution might be faster.)
def merge_list(a, b):
d = dict((val[0], set(val[1:])) for val in a)
result = []
for val in b:
k = val[0]
if k in d:
match = [x for x in val[1:] if x - 1 in d[k]]
if match:
result.append([k] + match)
return result
Similar to the other answers, this will first convert one of the lists to a dictionary with the first element of each inner list as the key and the remainder of the list as the value. Then we walk through the other list and if the first element exists as a key in the dictionary, we find all values that meet your criteria using the list comprehension and if there were any, add an entry to the result list which is returned at the end.

List slicing in python every other value

Suppose I have a list x = [1,2,3] and I want to output every other value than the indexed one, is there a list operation I can use?, ie: x[0]=> [2,3], x[1] => [1,3], x[2] =>[1,2] ?
You could use this:
def exclude(l, e):
return [v for i, v in enumerate(l) if i != e]
>>> exclude(range(10), 3)
[0, 1, 2, 4, 5, 6, 7, 8, 9]
You could do it with a slice, but I'd be tempted to try:
a = [1, 2, 3]
b = a[:]
del b[1]
edit
The above does "technically" use a slice operation, which happens to be on list objects in effect a shallow-copy.
What's more flexible and shouldn't have any downsides is to use:
a = [1, 2, 3]
b = list(a)
del b[1]
The list builtin works on any iterable (while the slice operation [:] works on lists or those that are indexable) so that you could even extend it to constructs such as:
>>> a = '123'
>>> b = list(a)
>>> del b[0]
>>> ''.join(b)
'23'
You could use x[:i] + x[i+1:]:
In [8]: x = [1, 2, 3]
In [9]: i = 0
In [10]: x[:i] + x[i+1:]
Out[10]: [2, 3]
Depending on the context, x.pop(i) might also be useful. It modifies the list in place by removing and returning the i-th element. If you don't need the element, del x[i] is also an option.
>>> x = [1, 2, 3]
>>> x[:1] + x[2:]
[1, 3]
my_list = [1, 2, 3]
my_list.remove(my_list[_index_]) #_index_ is the index you want to remove
Such that: my_list.remove(my_list[0]) would yield [2, 3],
my_list.remove(my_list[1]) would yield [0, 3], and
my_list.remove(my_list[2]) would yield [1, 2].
So you want every value except the indexed value:
Where i is the index:
>>> list = [1,2,3,4,5,6,7,8]
>>> [x for x in list if not x == list[i]]
This will give you a list with no instances of the i't element, so e.g.:
>>> i = 2
>>> list = [1,2,3,4,5,6,7,1,2,3,4,5,6,7]
>>> [x for x in list if not x == list[i]]
[1, 2, 4, 5, 6, 7, 1, 2, 4, 5, 6, 7]
note how 3 is not in that list at all.
Every other is
x[::2], start at 0
x[1::2], start at 1

Categories