How to XOR two lists in Python? [duplicate] - python

This question already has answers here:
Comparing two lists and only printing the differences? (XORing two lists)
(6 answers)
Closed 2 years ago.
I've got two lists, for example:
a = ['hello','world']
b = ['hello','world','im','steve']
If I want to create a third list that only contains elements NOT in both:
c = ['im','steve']
How do I do this if the order of the elements IS important? I know I can use sets but they keep throwing out the order of my lists. I could use ' '.join(list) to convert them to strings but not sure how to do this operation in that format either.

You can concatenate the lists and use list comprehension:
a = ['hello','world']
b = ['hello','world','im','steve']
final_vals = [i for i in a+b if i not in a or i not in b]
Output:
['im', 'steve']

Option 1: set method (recommended)
Sets have a symmetric_difference method that exclusively return elements from either a or b. Order can be preserved with a list comprehension for a concatenated list a + b.
comp = set(a).symmetric_difference(b)
[x for x in a + b if x in comp]
# ['im', 'steve']
Option 2: pathlib method
For reference, another way to diff two lists might be with pathlib.Path.relative_to method:
import pathlib
p = pathlib.Path(*b)
r = p.relative_to(*a)
list(r.parts)
# ['im', 'steve']
Note: b is the longer list. This option is potentially less efficient than a simple list comprehension.

Add two lists together and minus the intersection part if it shows in the new list. Order is preserved.
c = a + b
for v in set(a).intersection(set(b)):
while v in c:
c.remove(v)

a = ['hello','world']
b = ['hello','world','im','steve']
a = set(a)
b = set(b)
print(a.symmetric_difference(b))
This code print elements that are only in one of the tables.
Look here:
https://learnpython.org/en/Sets

You could also just create a function that filters elements from l1 that don't exist in l2, and call it twice with the arguments flipped:
a = ['hello','world', 'foo']
b = ['hello','world','im','steve']
def difference(l1, l2):
return list(filter(lambda x: x not in l2, l1))
print(difference(a, b) + difference(b, a))
# ['foo', 'im', 'steve']
If you don't wish to use filter(), a simple list comprehension like this also works:
[item for item in l1 if item not in l2]

The question is not very clear, indeed, and probably you're good with #Ajax1234 's answer, but here's another "take" on it.
If you wanna compare positions (kind of what a bit-wise XOR would do) you can do something like getting the shortest list, iterate checking position by position with the longest list (check the same position in the longest list matches the word in the shortest list) and then add the remainder (the "unwalked" part of the longest list). Something like the following:
a = ['hello', 'world']
b = ['hello', 'world', 'im', 'steve']
min_list = a if len(a) < len(b) else b
max_list = b if len(b) > len(a) else a
results = []
for i, item in enumerate(min_list):
# Iterate through the shortest list to avoid IndexError(s)
if min_list[i] != max_list[i]:
results.append(min_list[i])
results.append(max_list[i])
results.extend(max_list[i + 1:])
print(results)
# Prints: ['im', 'steve']
However, then you have the problem of what to do if the same positions don't match. I mean... What to do in that case? In the code above, I just added both entries to the results list, which means for the following inputs:
a = ['hello', 'foo']
b = ['hello', 'world', 'im', 'steve']
would output:
>>> ['foo', 'world', 'im', 'steve']
(notice both foo from list a and world from list b have been added)

Using standard for loop to check for items not in one or the other list (may be more understandable than list comprehension):
a = ['hello','world', 'foo']
b = ['hello','world','im','steve']
c = a+b
ans = []
for i in c:
if i not in a or i not in b:
ans.append(i)
print(ans)
Output:
['foo', 'im', 'steve']

I recommend, using ^ operator with sets, like set(a) ^ set(b), Example (demo):
>>> a = ['hello','world']
>>> b = ['hello','world','im','steve']
>>> set(a) ^ set(b)
{'steve', 'im'}
>>> sorted(set(a) ^ set(b),key=max([a,b],key=len).index)
['im', 'steve']
>>>
https://docs.python.org/2/library/stdtypes.html#frozenset.symmetric_difference

Related

Adding html tags with regex/python, sub code not working [duplicate]

Now I know that it is not safe to modify the list during an iterative looping. However, suppose I have a list of strings, and I want to strip the strings themselves. Does replacement of mutable values count as modification?
See Scope of python variable in for loop for a related problem: assigning to the iteration variable does not modify the underlying sequence, and also does not impact future iteration.
Since the loop below only modifies elements already seen, it would be considered acceptable:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Which is different from:
a[:] = [s.strip() for s in a]
in that it doesn't require the creation of a temporary list and an assignment of it to replace the original, although it does require more indexing operations.
Caution: Although you can modify entries this way, you can't change the number of items in the list without risking the chance of encountering problems.
Here's an example of what I mean—deleting an entry messes-up the indexing from that point on:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(The result is wrong because it didn't delete all the items it should have.)
Update
Since this is a fairly popular answer, here's how to effectively delete entries "in-place" (even though that's not exactly the question):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
See How to remove items from a list while iterating?.
It's considered poor form. Use a list comprehension instead, with slice assignment if you need to retain existing references to the list.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
One more for loop variant, looks cleaner to me than one with enumerate():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
Modifying each element while iterating a list is fine, as long as you do not change add/remove elements to list.
You can use list comprehension:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
or just do the C-style for loop:
for index, item in enumerate(l):
l[index] = item.strip()
The answer given by Ignacio Vazquez-Abrams is really good. It can be further illustrated by this example. Imagine that:
A list with two vectors is given to you.
You would like to traverse the list and reverse the order of each one of the arrays.
Let's say you have:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # This command does not reverse the string.
print([v,b])
You will get:
[array([1, 2, 3, 4]), array([3, 4, 6])]
On the other hand, if you do:
v = np.array([1,2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # This command reverses the string.
print([v,b])
The result is:
[array([4, 3, 2, 1]), array([6, 4, 3])]
No you wouldn't alter the "content" of the list, if you could mutate strings that way. But in Python they are not mutable. Any string operation returns a new string.
If you had a list of objects you knew were mutable, you could do this as long as you don't change the actual contents of the list.
Thus you will need to do a map of some sort. If you use a generator expression it [the operation] will be done as you iterate and you will save memory.
You can do something like this:
a = [1,2,3,4,5]
b = [i**2 for i in a]
It's called a list comprehension, to make it easier for you to loop inside a list.
It is not clear from your question what the criteria for deciding what strings to remove is, but if you have or can make a list of the strings that you want to remove , you could do the following:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
which changes my_strings to ['a', 'c', 'e']
In short, to do modification on the list while iterating the same list.
list[:] = ["Modify the list" for each_element in list "Condition Check"]
example:
list[:] = [list.remove(each_element) for each_element in list if each_element in ["data1", "data2"]]
Something I just discovered - when looping over a list of mutable types (such as dictionaries) you can just use a normal for loop like this:
l = [{"n": 1}, {"n": 2}]
for d in l:
d["n"] += 1
print(l)
# prints [{"n": 2}, {"n": 1}]

Nested List -Python

I have two list . i want to compare with each other with the list index[1][2][3] of "a" of each list with other list index[1][2][3] of "b" .If its a match then ignore , if not then return the whole list.
a = [['Eth1/1/13', 'Marketing', 'connected', '10', 'full', 'a-1000'], ['Eth1/1/14', 'NETFLOW02', 'connected', '10', 'full', '100']]
b = [['Eth1/1/13', 'NETFLOW02', 'connected', '15', 'full', '100'], ['Eth1/1/14', 'Marketing', 'connected', '10', 'full', 'a-1000']]
Desired Output :
Diff a:
Eth1/1/14 NETFLOW02 connected 10 full 100
Diff b:
Eth1/1/13 NETFLOW02 connected 15 full 100
What i am trying :
p = [i for i in a if i not in b]
for item in p:
print item[0]
print "\n++++++++++++++++++++++++++++++\n"
q = [i for i in b if i not in a]
for item in q:
print item[0]
tried below but only managed to match index 1 of inner list , index 2 and 3 still need to be matched..
[o for o in a if o[1] not in [n[1] for n in b]
I am not getting the expected output.Any idea how to do this ?
for sublista in a:
if not any(sublista[1:4] == sublistb[1:4] for sublistb in b):
print(sublista)
You need an inner loop so that each sub-list from list a can be compared to each sub-list in list b. The inner loop is accomplished with a generator expression. Slices are used to to compare only a portion of the sub-lists. The built-in function any consumes the generator expression; it is lazy and will return True with the first True equivalency comparison. This will print each sub-list in a that does not have a match in b - to print each sub-list in b that does not have a match in a, put b in the outer loop and a in the inner loop.
Here is an equivalent Without using a generator expression or any:
for sublista in a:
equal = False
for sublistb in b:
if sublista[1:4] == sublistb[1:4]:
break
else:
print(sublista)
Sometimes it is nice to use operator.itemgetter so you can use names for the slices which can make the code more intelligible.:
import operator
good_stuff = operator.itemgetter(1,2,3)
for sublista in a:
if not any(good_stuff(sublista) == good_stuff(sublistb) for sublistb in b):
print(sublista)
itertools.product conveniently generates pairs and can be used as a substitute for the nested loops above. The following uses a dictionary (defaultdict) to hold comparison results for each sublist in a and b, then checks to see if there were matches - it does both the a to b and b to a comparisons.
import itertools, collections
pairs = itertools.product(a, b)
results = collections.defaultdict(list)
for sub_one, sub_two in pairs:
comparison = good_stuff(sub_one) == good_stuff(sub_two)
results[tuple(sub_one)].append(comparison)
results[tuple(sub_two)].append(comparison)
for sublist, comparisons in results.items():
if any(comparisons):
continue
print(sublist)
# or
from pprint import pprint
results = [sublist for sublist, comparisons in results.items() if not any(comparisons)]
pprint(results)
for v in a,b:
for items in v:
if 'NETFLOW02' in items:
print('\t'.join(items))
I'm not sure this is ok for your purpose but you seems to want to capture the results of a network interface called NETFLOW02 from these two lists.
I'm sure there's probably a reason this is unacceptable but you could also expand this to include other keywords in longer lists, well, any length of lists that are nested as far as explained in your question. To do this, you would need to create another list, hypothetically keywords = ['NETFLOW02','ETH01']
Then we simply iterate this list also.
results = []
for v in a,b:
for item in v:
for kw in keywords:
if kw in item:
results.append(item)
print('\t'.join(item))
print(results)

common elements in two lists where elements are the same

I have two lists like thw following:
a=['not','not','not','not']
b=['not','not']
and I have to find the len of the list containing the intesection of the two above list, so that the result is:
intersection=['not','not']
len(intersection)
2
Now the problem is that I have tried filter(lambda x: x in a,b) and filter (lambda x: x in b,a) but when one of two list in longer than the other I do not get an intersection but just a membership checking. In the example above, since all the members of a are in b I get a len of common elements of 4; what I instead want is the intersection, which is len 2.
Using set().intersection(set()) would instead create a set, which is not what I want since all the elements are the same.
Can you suggest me any valuable and compact solution to the problem?
If you don't mind using collections.Counter, then you could have a solution like
>>> import collections
>>> a=['not','not','not','not']
>>> b=['not','not']
>>> c1 = collections.Counter(a)
>>> c2 = collections.Counter(b)
and then index by 'not'
>>> c1['not'] + c2['not']
6
For the intersection, you need to
>>> (c1 & c2) ['not']
2
I don't see any particularly compact way to compute this. Let's just go for a solution first.
The intersection is some sublist of the shorter list (e.g. b). Now, for better performance when the shorter list is not extremely short, make the longer list a set (e.g. set(a)). The intersection can then be expressed as a list comprehension of those items in the shorter list which are also in the longer set:
def common_elements(a, b):
shorter, longer = (a, b) if len(a)<len(b) else (b, a)
longer = set(longer)
intersection = [item for item in shorter if item in longer]
return intersection
a = ['not','not','not','not']
b = ['not','not']
print(common_elements(a,b))
Have you considered the following approach?
a = ['not','not','not','not']
b = ['not','not']
min(len(a), len(b))
# 2
Since all the elements are the same, the number of common elements is just the minimum of the lengths of both lists.
Do it by set. First make those lists to sets and then take their intersection. Now there might be repetitions in the intersection. So for each elements in intersection take the minimum repetitions in a and b.
>>> a=['not','not','not','not']
>>> b=['not','not']
>>> def myIntersection(A,B):
... setIn = set(A).intersection(set(B))
... rt = []
... for i in setIn:
... for j in range(min(A.count(i),B.count(i))):
... rt.append(i)
... return rt
...
>>> myIntersection(a,b)
['not', 'not']

How to copy data in Python

After entering a command I am given data, that I then transform into a list. Once transformed into a list, how do I copy ALL of the data from that list [A], and save it - so when I enter a command and am given a second list of data [B], I can compare the two; and have data that is the same from the two lists cancel out - so what is not similar between [A] & [B] is output. For example...
List [A]
1
2
3
List [B]
1
2
3
4
Using Python, I now want to compare the two lists to each other, and then output the differences.
Output = 4
Hopefully this makes sense!
You can use set operations.
a = [1,2,3]
b = [1,2,3,4]
print set(b) - set(a)
to output the data in list format you can use the following print statement
print list(set(b) - set(a))
>>> b=[1,2,3,4]
>>> a=[1,2,3]
>>> [x for x in b if x not in a]
[4]
for element in b:
if element in a:
a.remove(element)
This answer will return a list not a set, and should take duplicates into account. That way [1,2,1] - [1,2] returns [1] not [].
Try itertools.izip_longest
import itertools
a = [1,2,3]
b = [1,2,3,4]
[y for x, y in itertools.izip_longest(a, b) if x != y]
# [4]
You could easily modify this further to return a duple for each difference, where the first item in the duple is the position in b and the second item is the value.
[(i, pair[1]) for i, pair in enumerate(itertools.izip_longest(a, b)) if pair[0] != pair[1]]
# [(3, 4)]
For entering the data use a loop:
def enterList():
result = []
while True:
value = raw_input()
if value:
result.append(value)
else:
return result
A = enterList()
B = enterList()
For comparing you can use zip to build pairs and compare each of them:
for a, b in zip(A, B):
if a != b:
print a, "!=", b
This will truncate the comparison at the length of the shorter list; use the solution in another answer given here using itertools.izip_longest() to handle that.

Python list difference

I am trying to find all the elements that are in list A and not in list B.
I thought something like newList = list(set(a) & !set(b)) or newList = list(set(a) & (not set(b))) would work, but it's not.
If there a better way to achieve what I'm trying to do other than this?
newList = []
for item in a:
if item not in b:
newList.append(item)
Also important, it needs to be done in Python 2.6
You're looking for the set difference:
newList = list(set(a).difference(b))
Alternatively, use the minus operator:
list(set(a) - set(b))
Did you try
list(set(a) - set(b))
Here is a list of all Python set operations.
But this unnecessarily creates a new set for b. As #phihag mentions, difference method would prevent this.
If you care about maintaining order:
def list_difference(a, b):
# returns new list of items in a that are not in b
b = set(b)
return [x for x in a if x not in b]
>>> list1 = [1,2,3,4,5]
>>> list2 = [4,5,6,7,8]
>>> print list(set(list1)-set(list2))
[1, 2, 3]

Categories

Resources