getting the difference between lists, keeping non-unique values - python

I am looking to get the difference between two lists.
I am looking for a solution like this only I want to consider non-unique list values.
x = [1, 1, 2, 2, 3]
y = [1, 2]
# i want
z = x - y
# z = [1, 2, 3]
The solution above my code turns the two lists into sets which allows the - operator to work on them but removes non unique values from the lists. Can you think of a simple 'one liner' solution that does what im looking for?

You could use collections.Counter to find the counts of elements in each list. Then you can take the difference and reconstruct a list from the results.
>>> from collections import Counter
>>> x = [1, 1, 2, 2, 3]
>>> y = [1, 2]
>>> [k for _ in range(v) for k,v in (Counter(x) - Counter(y)).iteritems()]
[1, 2, 3]
The drawback being, the order of the result has no real correlation with the order of the input lists. The fact that the result shown above looks sorted is implementation-dependent and possibly only a coincidence.

might not be fancy, first thing that came to mind..
x=[1,1,2,2,3]
y=[1,2]
_ = [ x.remove(n) for n in y if n in x ]
x
[1,2,3]

Here's my take:
x = [1, 1, 2, 2, 3]
y = [1, 2]
z = [n for n in y if (n in x) and x.remove(n)] + x
print(z) # -> [1, 2, 3]
x = [1, 1, 1, 2]
y = [1]
z = [n for n in y if (n in x) and x.remove(n)] + x
print(z) # -> [1, 1, 2]

You just described the union of two sets, so use set:
>>> list(set(x).union(set(y)))
[1, 2, 3]

Related

How to check if one list starts with another?

If I have two lists in Python, [0, 1] and [0, 1, 2, 3], how do I check if the first list starts with the second?
I know how to do this with strings, just use the startswith method. But apparently you can't do that for lists.
Is there a one-liner that does what I described?
Just iterate them parallelly and check that the corresponding values are equal. You can create a generator expression for the equality iterating using zip, along with all:
>>> a = [0, 1]
>>> b = [0, 1, 2, 3]
>>> all(i==j for i,j in zip(a,b))
True
This works because zip stops when the shortest iterable is exhausted.
I think this is what you meant
if the list x starts with the list y
>>> x[0:len(y)] == y
True
>>> x
[0, 1, 2, 3]
>>> y
[0, 1]
>>> a = [0, 1]
>>> b = [0, 1, 2, 3]
>>> a[:min(len(a), len(b))] == b[:min(len(a), len(b))]
True

Iteratively compare one element to all others in a Python list

I want to compare every element of the list to the rest of the elements. For this, I need to iteratively exclude one element. Specifically, I want to calculate the mean of all elements when one value is removed. E.g.:
mylist = [1, 2, 3, 4]
Mean values:
[2, 3, 4] = 3 (excludes 1)
[1, 3, 4] = 2.66 (excludes 2)
[1, 2, 4] = 2.44 (excludes 3)
[1, 2, 3] = 2 (excludes 4)
Is there an intuitive way of doing this, without something like
[mylist[i-1:i] + mylist[i+1:] for i in range(len(mylist))]?
Maths to the rescue!
The mean of a list is sum(myList) / len(myList).
If you remove an element x from myList, the sum becomes sum(myList) - x. Now the mean of the remaining elements is (sum(myList) - x) / (len(myList) - 1)
For all elements:
newList = [(sum(myList) - x) / (len(myList) - 1) for x in myList]
Or for O(n),
s = sum(myList)
newLen = len(myList) - 1
newList = [(s - x) / newLen for x in myList]
I found a way using a collections.deque and "rotate" it, and removing the first element at every iteration of the loop:
mylist = [1, 2, 3, 4]
from collections import deque
for i in range(len(mylist)):
d = deque(mylist)
d.rotate(-i)
first, *rest = d
print(f'{rest}: {sum(rest)/len(rest):.2f}')
[2, 3, 4]: 3.00
[3, 4, 1]: 2.67
[4, 1, 2]: 2.33
[1, 2, 3]: 2.00

Multiplication of all elements in two lists

I want to multiply each number of list1 with each number of list2.
For example:
[1,2]*[1,2,3] should return something like this: [1,2,3,2,4,6]
I just want to know if there is any special function to calculate this, as it would take a lot of time to calculate this using a for loop.
A simple nested comprehension will work:
lst1, lst2 = [1, 2], [1, 2, 3]
[x * y for x in lst1 for y in lst2]
# [1, 2, 3, 2, 4, 6]
To get all the pairs (the cartesian product) from the two lists, you can also use itertools.product:
from itertools import product
[x * y for x, y in product(lst1, lst2)]
# [1, 2, 3, 2, 4, 6]
You could also do this using dot products, as provided by numpy (I include this as an answer because you said you are looking for any special function, and are looking to optimize speed, though I agree it's not the most readable or straightforward method):
import numpy as np
lst1, lst2 = [1, 2], [1, 2, 3]
np.dot(np.array([lst1]).T, np.array([lst2])).flatten().tolist()
#[1, 2, 3, 2, 4, 6]
try this:
import itertools
a = [1, 2]
b = [1, 2, 3]
result = []
for n in a:
m = map(lambda x,y: x*y, b, itertools.repeat(n))
result.extend(m)

Average difference between ints in two lists in one line - Python

There are two non-empty lists, containing only ints, both have the same length.
Our function needs to return the average absolute difference between ints of same index.
For example, for the lists [1, 2, 3, 4] and [1, 1, 1, 1], the answer will be 1.5.
The function needs to be completed in one line.
I had a little something that does that, but as you can probably guess, it's not a one-liner:
def avg_diff(a, b):
sd = 0.0
for x, y in zip(a, b):
sd += abs(x - y)
return sd / len(a)
Thanks.
In Python 3.4 we got some statistic functions in the standard library, including statistics.mean.
Using this function and a generator-expression:
from statistics import mean
a = [1, 2, 3, 4]
b = [1, 1, 1, 1]
mean(abs(x - y) for x, y in zip(a, b))
# 1.5
a = [1, 2, 3, 4]
b = [1, 1, 1, 1]
sum([abs(i - j) for i, j in zip(a,b)]) / float(len(a))
If you are happy to use a 3rd party library, numpy provides one way:
import numpy as np
A = np.array([1, 2, 3, 4])
B = np.array([1, 1, 1, 1])
res = np.mean(np.abs(A - B))
# 1.5
Using the in-built sum and len functions on list:
lst1 = [1, 2, 3, 4]
lst2 = [1, 1, 1, 1]
diff = [abs(x-y) for x, y in zip(lst1, lst2)] # find index-wise differences
print(sum(diff)/len(diff)) # divide sum of differences by total
# 1.5

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