Difference between list of lists - python

I have two lists
A=[['1','1'],['2','1'],['3','2']]
B=[['1','1'],['2','2']]
I want to perform A-B operation on these comparing only first element.
so A-B should give
Output=[['3', '2']]
So far, I could do only on row comparison
[x for x in A if not x in B]
which gives output as [['2', '1'], ['3', '2']]

This?
>>> [i for i in A if not any(i[0] == k for k, _ in B)]
[['3', '2']]
any() is used to check if the first element of each list is the same as any other value in every list in B. If it is, it returns True, but as we want the opposite of this, we use not any(...)

You can also use collections.OrderedDict and set difference here:
>>> from collections import OrderedDict
>>> dic1 = OrderedDict((k[0],k) for k in A)
>>> [dic1[x] for x in set(dic1) - set(y[0] for y in B)]
[['3', '2']]
Overall complexity is going to be O(max(len(A), len(B)))
If order doesn't matter then a normal dict is sufficient.

I could think of a different list comprehension
A=[['1','1'],['2','1'],['3','2']]
B=[['1','1'],['2','2']]
b = dict(B)
output_list = [item for item in A if item[0] not in b]
This is order preserving as well and can work even if there are duplicate fist elements in the inner list of A. Also it can be extended to check for exact pair if needed like this:
A=[['1','1'],['2','1'],['3','2']]
B=[['1','1'],['2','2']]
b = dict(B)
output_list = [item for item in A if item[0] not in b or b[item[0]] != item[1]]

Related

Easier way to check if an item from one list of tuples doesn't exist in another list of tuples in python

I have two lists of tuples, say,
list1 = [('item1',),('item2',),('item3',), ('item4',)] # Contains just one item per tuple
list2 = [('item1', 'd',),('item2', 'a',),('item3', 'f',)] # Contains multiple items per tuple
Expected output: 'item4' # Item that doesn't exist in list2
As shown in above example I want to check which item in tuples in list 1 does not exist in first index of tuples in list 2. What is the easiest way to do this without running two for loops?
Assuming your tuple structure is exactly as shown above, this would work:
tuple(set(x[0] for x in list1) - set(x[0] for x in list2))
or per #don't talk just code, better as set comprehensions:
tuple({x[0] for x in list1} - {x[0] for x in list2})
result:
('item4',)
This gives you {'item4'}:
next(zip(*list1)) - dict(list2).keys()
The next(zip(*list1)) gives you the tuple ('item1', 'item2', 'item3', 'item4').
The dict(list2).keys() gives you dict_keys(['item1', 'item2', 'item3']), which happily offers you set operations like that set difference.
Try it online!
This is the only way I can think of doing it, not sure if it helps though. I removed the commas in the items in list1 because I don't see why they are there and it affects the code.
list1 = [('item1'),('item2'),('item3'), ('item4')] # Contains just one item per tuple
list2 = [('item1', 'd',),('item2', 'a',),('item3', 'f',)] # Contains multiple items per tuple
not_in_tuple = []
OutputTuple = [(a) for a, b in list2]
for i in list1:
if i in OutputTuple:
pass
else:
not_in_tuple.append(i)
for i in not_in_tuple:
print(i)
You don't really have a choice but to loop over the two lists. Once efficient way could be to first construct a set of the first elements of list2:
items = {e[0] for e in list2}
list3 = list(filter(lambda x:x[0] not in items, list1))
Output:
>>> list3
[('item4',)]
Try set.difference:
>>> set(next(zip(*list1))).difference(dict(list2))
{'item4'}
>>>
Or even better:
>>> set(list1) ^ {x[:1] for x in list2}
{('item4',)}
>>>
that is a difference operation for sets:
set1 = set(j[0] for j in list1)
set2 = set(j[0] for j in list2)
result = set1.difference(set2)
output:
{'item4'}
for i in list1:
a=i[0]
for j in list2:
b=j[0]
if a==b:
break
else:
print(a)

How can it taken the specific args in lists of list?

for example we have;
L = [["Ak","154"],["Bm","200"],["Ck","250"], ["Ad","500"],["Ac","600"]]
I want to choose first element starting with 'A' I want to find their values which are in second element; see this output should like
["154","500","600"] or like [["154"],["500"],["600"]]
Filter and map with a list comprehension:
[b for a, b in L if a[0] == "A"]
Or, if you need to search for prefixes of more than one character:
[b for a, b in L if a.startswith("A")]
Another Solution Using map() and filter() functions
L = [["Ak","154"],["Bm","200"],["Ck","250"], ["Ad","500"],["Ac","600"]]
k = list(map(lambda y:y[1], list(filter(lambda x: x[0][0] == 'A' , L))))
Output:
['154', '500', '600']

Python - Return true if strings found in nested list

My goal is to return True/False if I am able to detect two items within a nested list.
E.g.
list1 = [['1', 'sjndnjd3', 'MSG1'], ['2', 'jdakb2', 'MSG1'], ['1', 'kbadkjh', 'MSG2']]
I want to iterate over this list to confirm if I can find '1' & 'MSG1' within a nested list. Important to note I only want this to return true if both items are found and if they're found within the same nested list.
I've tried various combinations of the below however I cannot get it quite right.
all(x in e for e in list1 for x in ['1', 'MSG1'])
Any assistance is greatly appreciated.
Try this:
contains = any([True for sublist in list1 if "1" in sublist and "MSG1" in sublist])
You can use set.issubset:
any(True for sub_list in list1 if {'1', 'MSG1'}.issubset(set(sub_list)))
You need to apply all to each test of 1 and MSG being in list1, so you need to rewrite your list comprehension as
found = [all(x in e for x in ['1', 'MSG1']) for e in list1]
# [True, False, False]
You can then test for any of those values being true:
any(found)
# True
You can make a function as follows, using sum and list's count method:
def str_in_nested(list_, string_1, string_2):
return sum(sub_list.count(string_1) and sub_list.count(string_2) for sub_list in list_) > 0
Applying this function to you current case:
>>> list1 = [['1', 'sjndnjd3', 'MSG1'], ['2', 'jdakb2', 'MSG1'], ['1', 'kbadkjh', 'MSG2']]
>>> str_in_nested(list1, '1', 'MSG1')
True
It's:
any(all(item in sublist for item in ['1', 'MSG1']) for sublist in list1)
Give this a try...
for item in list1:
all(i in item for i in sub)

Iterating over lists of lists in Python

I have a list of lists:
lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
I want to iterate over each element and perform some string operations on them for example:
replace("(", "")
I tried iterating over the list using:
for l1 in lst1:
for i in l1:
lst2.append(list(map(str.replace("(", ""), l1)))
I wanted the out result to be the same as original list of lists but without the parenthesis. Also, I am looking for a method in editing lists of lists and not really a specific solution to this question.
Thank you,
Edit:
Yes, you should use normal for-loops if you want to:
Preform multiple operations on each item contained in each sub-list.
Keep both the main list as well as the sub-lists as the same objects.
Below is a simple demonstration of how to do this:
main = [["(a)", "(b)", "(c)"], ["(d)", "(e)", "(f)", "(g)"]]
print id(main)
print id(main[0])
print id(main[1])
print
for sub in main:
for index,item in enumerate(sub):
### Preform operations ###
item = item.replace("(", "")
item = item.replace(")", "")
item *= 2
sub[index] = item # Reassign the item
print main
print
print id(main)
print id(main[0])
print id(main[1])
Output:
25321880
25321600
25276288
[['aa', 'bb', 'cc'], ['dd', 'ee', 'ff', 'gg']]
25321880
25321600
25276288
Use a nested list comprehension:
>>> lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
>>> id(lst1)
35863808
>>> lst1[:] = [[y.replace("(", "") for y in x] for x in lst1]
>>> lst1
[['a)', 'b)', 'c)'], ['d)', 'e)', 'f)', 'g)']]
>>> id(lst1)
35863808
>>>
The [:] will keep the list object the same.
I just did what you did, i used the fact that each element of a list can be assigned a new (or updated) value:
>>> lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
>>> for x in range(len(lst1)):
for y in range(len(lst1[x])):
lst1[x][y] = lst1[x][y].replace("(", "")
>>> lst1
[['a)', 'b)', 'c)'], ['d)', 'e)', 'f)', 'g)']]
EDIT
This is how you do it with the "real problem" that you mentioned in the comment:
a = [[(12.22, 12.122, 0.000)], [(1232.11, 123.1231, 0.000)]]
some_num = 10
for x in range(len(a)):
b = list(a[x][0])
for y in range(len(b)):
b[y] *= some_num
a[x] = tuple(b)
print(a)
OUTPUT:
[(122.2, 121.22, 0.0), (12321.099999999999, 1231.231, 0.0)]
^ All elements have been multiplied by a number and the original format is kept
This is how it works:
So you have the initial list 'a' that has two sublists each with only ONE element (the tuple that contains the x,y,z coordinates). I go through list 'a' and make the tuples a list and set them equal to 'b' (so the fourth line has a value of [12.22, 12.122, 0.000] the first time around (and the next tuple (as a list) the next time around).
Then I go through each of the elements in 'b' (the tuple converted into a list) and multiply each element in that tuple by a number with the use of the increment operator (+=, -=, /=, *=). Once this loop is done, I set that same position in the master list 'a' equal to the tuple of the previously converted tuple. < If this doesn't make sense, what I'm saying is that the initial tuples are converted into lists (then operated on), and then converter back to tuples (since you want it to end up with the same format as before).
Hope this helps!
>>> lst1 = [["(a)", "(b)", "(c)"],["(d)", "(e)", "(f)", "(g)"]]
>>> [[j.strip('()') for j in i] for i in lst1]
[['a', 'b', 'c'], ['d', 'e', 'f', 'g']]
>>> [[j.lstrip('(') for j in i] for i in lst1]
[['a)', 'b)', 'c)'], ['d)', 'e)', 'f)', 'g)']]

Converting an integer list into a string list

I am new to Python. I need to know how to convert a list of integers to a list of strings. So,
>>>list=[1,2,3,4]
I want to convert that list to this:
>>>print (list)
['1','2','3','4']
Also, can I add a list of strings to make it look something like this?
1234
You can use List Comprehension:
>>> my_list = [1, 2, 3, 4]
>>> [str(v) for v in my_list]
['1', '2', '3', '4']
or map():
>>> str_list = map(str, my_list)
>>> str_list
['1', '2', '3', '4']
In Python 3, you would need to use - list(map(str, my_list))
For 2nd part, you can use join():
>>> ''.join(str_list)
'1234'
And please don't name your list list. It shadows the built-in list.
>>>l=[1,2,3,4]
I've modified your example to not use the name list -- it shadows the actual builtin list, which will cause mysterious failures.
Here's how you make it into a list of strings:
l = [str(n) for n in l]
And here's how you make them all abut one another:
all_together = ''.join(l)
Using print:
>>> mylist = [1,2,3,4]
>>> print ('{}'*len(mylist)).format(*mylist)
1234
l = map(str,l)
will work, but may not make sense if you don't know what map is
l = [str(x) for x in l]
May make more sense at this time.
''.join(["1","2","3"]) == "123"

Categories