Match array values with array values in multi-dimensional array - python

I have 2 arrays:
[1, 2, 3, 4, 5]
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Is there a way I can find the number of sub-array in the second array which contains the values of the first array using Python?
For the above, it would be 2

You can try this:
s = [1, 2, 3, 4, 5]
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
final_val = len([i for i in a if any(b in s for b in i)])
Output:
2

Yes, for each element in the first array, you must check if it is in the sub-arrays of the second.
However, this is quite inefficient, so you can proceed like this:
For each sub array in second, check it it contains any element of First, if it is the case, add one to the count, and check the next sub array.
first = [1, 2, 3, 4, 5]
second = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
matches = 0
for sub in second:
for elt in sub:
if elt in first:
matches += 1
break
print(matches)

Related

Finding an element in nested python list and then replacing it

I have a nested list and I am trying to replace a certain element of the list with something else.
NL = [[1,2,3],
[4,5,6],
[7,8,9]];
Now, I need to update the list, let's say the user wants to change element at NL[1][1] (i.e. 5) to 'X'.
NL will be updated as
NL = [[1,2,3],
[4,'X',6],
[7,8,9]];`
I am having trouble trying to find the position of the element and then changing it. Any help is much appreciated.
Thanks
Using numpy:
NL = np.array(NL)
mask = np.where(NL == 5)
NL[mask] = 10
array([[ 1, 2, 3],
[ 4, 10, 6],
[ 7, 8, 9]])
Solution2:
def get_index(num, List):
for row, i in enumerate(List):
if num in i:
return row, i.index(num)
return -1
idx = get_index(5,NL)
if idx>0:
NL[idx[0]][idx[1]] = 7
[[1, 2, 3], [4, 7, 6], [7, 8, 9]]
Use 2 indexes, 1 for the what nested list you want and one for what element of the nested list you want.
So in this case you want the 2nd list's 2nd element:
NL[1][1]='X'
Output:
[[1, 2, 3], [4, 'X', 6], [7, 8, 9]]
Let's say you need to find the element 5 and want to replace it with 10.
We iterate through the outer list and then each inner-list's elements. Once we find the element we look for, we can replace it by the indexes. We use enumerate to have the indexes once we find a matching element.
The following code replaces ALL matching elements (all occurences of 5).
NL = [[1,2,3], [4,5,6], [7,8,9]]
print(NL) # prints: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for i, sublist in enumerate(NL):
for y, element in enumerate(sublist):
if element == 5:
NL[i][y] = 10
print(NL) # prints: [[1, 2, 3], [4, 10, 6], [7, 8, 9]]
This will replace only the first occurrence of item_to_replace. If you want it to replace in all sublist then remove the break statement from try block.
item_to_replace = 5
for lst in NL:
try:
index = lst.index(item_to_replace)
lst[index] = # your replacement for item_to_replace
break
except ValueError:
continue
You should access to element by indexes. You have 2D list (array) so you should use 2 indexes: NL[1][1] = "X".
Complete code:
NL = [[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
print("Original: {}".format(NL))
NL[1][1] = "X"
print("New: {}".format(NL))
Output:
>>> python3 test.py
Original: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
New: [[1, 2, 3], [4, 'X', 6], [7, 8, 9]]
just use NL[1][1] = 'X'
then print(NL)
I am having trouble trying to find the position of the element and then changing it.
Most of the answers here seem to have missed that part, and assumed you had the position.
You can use a nested list comprehension:
NL = [[1,2,3],
[4,5,6],
[7,8,9]]
NL = [['X' if i==5 else i for i in j] for j in NL]
print(NL)
Output:
[[1, 2, 3],
[4,'X',6],
[7, 8, 9]]

How to make new list of the numbers not appended into its own list?

If I have a multidimensional list called t and I append some numbers from the list into a new list called TC, how do I take all of the numbers that were not appended into the new list and put them in their own list, called nonTC? For example:
t = [[1, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]
And I write some conditions to append only some values from each list to create the new list, TC:
TC = [[3, 4, 6], [9, 7, 2], [5]]
How do I append the values not included in TC into its own list? So I would get:
nonTC = [[1, 5, 7],[4, 5],[3,4]]
You can use list comprehensions and a list of sets to filter your original list:
t = [[1, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]
# filter sets - each index corresponds to one inner list of t - the numbers in the
# set should be put into TC - those that are not go into nonTC
getem = [{3,4,6},{9,7,2},{5}]
TC = [ [p for p in part if p in getem[i]] for i,part in enumerate(t)]
print(TC)
nonTC = [ [p for p in part if p not in getem[i]] for i,part in enumerate(t)]
print(nonTC)
Output:
[[3, 4, 6], [9, 7, 2], [5]] # TC
[[1, 5, 7], [4, 5], [3, 4]] # nonTC
Readup:
list comprehensions
sets
enumerate(iterable)
And: Explanation of how nested list comprehension works?
Suggestion for other way to do it, creds to AChampion:
TC_1 = [[p for p in part if p in g] for g, part in zip(getem, t)]
nonTC_1 = [[p for p in part if p not in g] for g, part in zip(getem, t)]
See zip() - it essentially bundles the two lists into an iterable of tuples
( (t[0],getem[0]), (t[1],getem[1]) (t[2],getem[2]))
Add-On for multiple occurences - forfeiting list comp and sets:
t = [[1, 3, 4, 5, 6, 7, 3, 3, 3],[9, 7, 4, 5, 2], [3, 4, 5]]
# filter lists - each index corresponds to one inner list of t - the numbers in the list
# should be put into TC - those that are not go into nonTC - exactly with the amounts given
getem = [[3,3,4,6],[9,7,2],[5]]
from collections import Counter
TC = []
nonTC = []
for f, part in zip(getem,t):
TC.append([])
nonTC.append([])
c = Counter(f)
for num in part:
if c.get(num,0) > 0:
TC[-1].append(num)
c[num]-=1
else:
nonTC[-1].append(num)
print(TC) # [[3, 4, 6, 3], [9, 7, 2], [5]]
print(nonTC) # [[1, 5, 7, 3, 3], [4, 5], [3, 4]]
It needs only 1 pass over your items instead of 2 (seperate list comps) which makes it probably more efficient in the long run...
Just out of curiosity, using NumPy:
import numpy as np
t = [[1, 3, 4, 5, 6, 7],[9, 7, 4, 5, 2], [3, 4, 5]]
TC = [[3, 4, 6], [9, 7, 2], [5]]
print([np.setdiff1d(a, b) for a, b in zip(t, TC)])
#=> [array([1, 5, 7]), array([4, 5]), array([3, 4])]

Subtract previous list from current list in a list of lists loop

I have a list of dataframes with data duplicating in every next dataframe within list which I need to subtract between themselves
the_list[0] = [1, 2, 3]
the_list[1] = [1, 2, 3, 4, 5, 6, 7]
There are also df headers. Dataframes are only different in number of rows.
Wanted solution:
the_list[0] = [1, 2, 3]
the_list[1] = [4, 5, 6, 7]
Due to the fact that my list of lists, the_list, contains several dataframes, I have to work backward and go from the last df to first with first remaining intact.
My current code (estwin is the_list):
estwin = [df1, df2, df3, df4]
output=([])
estwin.reverse()
for i in range(len(estwin) -1):
difference = Diff(estwin[i], estwin[i+1])
output.append(difference)
return(output)
def Diff(li_bigger, li_smaller):
c = [x for x in li_bigger if x not in li_smaller]
return (c)
Currently, the result is an empty list. I need an updated the_list that contains only the differences (no duplicate values between lists).
You should not need to go backward for this problem, it is easier to keep track of what you have already seen going forward.
Keep a set that gets updated with new items as you traverse through each list, and use it to filter out the items that should be present in the output.
list1 = [1,2,3]
list2 = [1,2,3,4,5,6,7]
estwin = [list1, list2]
lookup = set() #to check which items/numbers have already been seen.
output = []
for lst in estwin:
updated_lst = [i for i in lst if i not in lookup] #only new items present
lookup.update(updated_lst)
output.append(updated_lst)
print(output) #[[1, 2, 3], [4, 5, 6, 7]]
Your code is not runnable, but if I guess what you meant to write, it works, except that you have one bug in your algorithm:
the_list = [
[1, 2, 3],
[1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7, 8, 9]
]
def process(lists):
output = []
lists.reverse()
for i in range(len(lists)-1):
difference = diff(lists[i], lists[i+1])
output.append(difference)
# BUGFIX: Always add first list (now last becuase of reverse)
output.append(lists[-1])
output.reverse()
return output
def diff(li_bigger, li_smaller):
return [x for x in li_bigger if x not in li_smaller]
print(the_list)
print(process(the_list))
Output:
[[1, 2, 3], [1, 2, 3, 4, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7, 8, 9]]
[[1, 2, 3], [4, 5, 6, 7], [8, 9]]
One-liner:
from itertools import chain
l = [[1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
new_l = [sorted(list(set(v).difference(chain.from_iterable(l[:num]))))
for num, v in enumerate(l)]
print(new_l)
# [[1, 2], [3], [4], [5]]

Union list of lists without duplicates

I have got list of lists. I need to get all combinations of that lists from 2 of N to N of N.
I'm searching for it with itertools.combinations. After this I got list of lists and I need to combine them without duplicates.
For example I have got array:
a = np.array([[1,4,7],[8,2,5],[8,1,4,6],[8,1,3,5],
[2,3,4,7],[2,5,6,7],[2,3,4,6,8],[1,3,5,6,7]])
I'm searching for all 3 elements combinations:
a2 = list(itertools.combinations(a, 3))
a2[:5]
[([1, 4, 7], [8, 2, 5], [8, 1, 4, 6]),
([1, 4, 7], [8, 2, 5], [8, 1, 3, 5]),
([1, 4, 7], [8, 2, 5], [2, 3, 4, 7]),
([1, 4, 7], [8, 2, 5], [2, 5, 6, 7]),
([1, 4, 7], [8, 2, 5], [2, 3, 4, 6, 8])]
The length of this array: 56.
I need to combine every list in this array without duplicates.
For exmple for a2[0] input:
([1, 4, 7], [8, 2, 5], [8, 1, 4, 6])
output:
[1, 2, 4, 5, 6, 7, 8]
And so all 56 elements.
I tried to do it with set:
arr = list(itertools.combinations(a,3))
for i in arr:
arrnew[i].append(list(set().union(arr[i][:3])))
But I had got error:
TypeError Traceback (most recent call last)
<ipython-input-75-4049ddb4c0be> in <module>()
3 arrnew = []
4 for i in arr:
----> 5 for j in arr[i]:
6 arrnew[i].append(list(set().union(arr[:n])))
TypeError: list indices must be integers or slices, not tuple
I need function for N combinations, that returns new combined array.
But I don't know how to do this because of this error.
Is there way to solve this error or another way to solve this task?
A small function which solves it:
def unique_comb(a):
return list(set(itertools.chain(*a)))
For example:
unique_comb(([1, 4, 7], [8, 2, 5], [8, 1, 4, 6]))
If you want to pass a list as an argument to the function, rather than a list inside a tuple, just remove the * (which unpacks the list).
If you want to apply it to the entire array in one statement without defining a function:
a3 = [list(set(itertools.chain(*row))) for row in a2]
Flatting a tuple of lists:
from itertools import chain
new_tuple = [ list(set(chain.from_iterable(each_tuple))) for each_tuple in main_tuple_coll ]
I think this might solve your problem.
Flatten list combinations
comb = []
for line in a2[:3]:
l = list(set([x for y in line for x in y]))
comb.append(l)
comb
[out]
[[1, 2, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 7, 8], [1, 2, 3, 4, 5, 7, 8]]
The issue with:
arr = list(itertools.combinations(a,3))
for i in arr:
arrnew[i].append(list(set().union(arr[i][:3])))
Is that i is not the index of the item but the item in the list itself.
What you need is:
import itertools
import numpy as np
a = np.array([[1,4,7],[8,2,5],[8,1,4,6],[8,1,3,5],
[2,3,4,7],[2,5,6,7],[2,3,4,6,8],[1,3,5,6,7]])
arrnew = []
for item in itertools.combinations(a,3):
arrnew.append(list(set().union(*item)))
The result arrnew contains 56 items. Some are equal but none contain duplicates.
I would suggest using sorted rather than list to ensure that the items in each combined list are in ascending order.

How to modify the elements in a list within list

I am very new to Python, trying to learn the basics. Have a doubt about the list.
Have a list:
L = [[1,2,3],[4,5,6],[3,4,6]]
The output should be:
[[2,4,6],[8,10,12],[6,8,12]]
The code that works for me is the following
for x in range(len(L)):
for y in range(len(L[x])):
L[x][y] = L[x][y] + L[x][y]
print L
It gives the output [[2,4,6],[8,10,12],[6,8,12]].
Now I want the same output with a different code:
for x in L:
a = L.index(x)
for y in L[a]:
b = L[a].index(y)
L[a][b] = L[a][b] + L[a][b]
print L
With the above code the output obtained is:
[[4,2,6],[8,10,12],[12,8,6]]
I tried to debug about the above output.
I put a print statement above the line "L[a][b] = L[a][b] + L[a][b]" for printing a and b. I was surprised to see the values of a and b are :
0,0
0,0
0,2
1,0
1,1
1,2
2,0
2,1
2,0
Again if I comment out the line "L[a][b] = L[a][b] + L[a][b]" then the values of a and b are as expected:
0,0
0,1
0,2
1,0
1,1
1,2
2,0
2,1
2,2
I suspect this might be happening due to the scope of variable in python and tried to study few stuffs about scoping in python. But I didn't get appropriate answer neither for scoping or the above question.
You modifying your list with statement - L[a][b] = L[a][b] + L[a][b]
e.g. -
L = [[1, 2, 3], [4, 5, 6], [3, 4, 6]]
L[0][0] = 1 initially
Then you modify it as L[0][0] = 2
L = [[2, 2, 3], [4, 5, 6], [3, 4, 6]]
In next loop you search index for 2, which is 0,0 now, Because you modified list L.
I tried to print L along with a,b in your example. Result explains the behavior -
0 0
[[1, 2, 3], [4, 5, 6], [3, 4, 6]]
0 0
[[2, 2, 3], [4, 5, 6], [3, 4, 6]]
0 2
[[4, 2, 3], [4, 5, 6], [3, 4, 6]]
1 0
[[4, 2, 6], [4, 5, 6], [3, 4, 6]]
1 1
[[4, 2, 6], [8, 5, 6], [3, 4, 6]]
1 2
[[4, 2, 6], [8, 10, 6], [3, 4, 6]]
2 0
[[4, 2, 6], [8, 10, 12], [3, 4, 6]]
2 1
[[4, 2, 6], [8, 10, 12], [6, 4, 6]]
2 0
[[4, 2, 6], [8, 10, 12], [6, 8, 6]]
As other people have explained, when you use the index function, it finds the first occurrence of the value you are search for. So the first time through you're loop (for the first row), it looks like
b = 1
[1,2,3].find(1) # returns index 0
#Then you modify the first element of the list
b = 2
[2,2,3].find(2) #returns index 0 again!
For getting the indices in an easier, more deterministic way, you can use the enumerate function on a list. It will provided you with an iterator that returns the index AND value as you move throughout a list.
for rowInd, x in enumerate(L):
for colInd, y in enumerate(x):
L[rowInd][colInd] = y + y
Note that this will do it in place, as in your original solution.
L = [[2, 4, 6], [8, 10, 12], [6, 8, 12]]
The best way to achieved your desired output is to use a list comprehension. You could do as follows:
L = [[1,2,3], [4,5,6], [3,4,6]]
answer = [[2*el for el in sublist] for sublist in L]
print(answer)
Output
[[2, 4, 6], [8, 10, 12], [6, 8, 12]]
This iterates over each sublist in your list L and multiplies each el in the sublist by 2, thus achieving the desired result.
I think the following piece of code might be better
for x in L: #iterating over the orig list
for y in x: #iterating over the inner list
[x][y] = [x][y] + [x][y]
If you insist on using your second method, then you need to store the results in a temporary variable:
L = [[1, 2, 3], [4, 5, 6], [3, 4, 6]]
M = [[0 for y in range(3)] for x in range(3)]
for x in L:
a = L.index(x)
for y in L[a]:
b = L[a].index(y)
M[a][b] = L[a][b] + L[a][b]
L = M
print L
Output:
[[2, 4, 6], [8, 10, 12], [6, 8, 12]]

Categories