I would like to find the number of unique lists within a nested list in a nopython numba function, e.g:
from collections import Counter
def number_of_unique_lists_v1(a):
uniques = Counter(tuple(item) for item in a)
number = len(uniques.keys())
return number
print(number_of_unique_lists_v1([[1,2,3],[1,2],[3,4],[1,2,3])
>>> 3
or
def number_of_unique_lists_v2(a):
uniques = [list(x) for x in set(tuple(x) for x in a)]
number = len(uniques)
return number
print(number_of_unique_lists_v2([[1,2,3],[1,2],[3,4],[1,2,3])
>>> 3
Unfortunately, both ideas don't work with #nb.njit. How can I make it work?
Edit:
Using the approach of mpw2 I found that in principle the following code works:
from numba.typed import List
#nb.njit
def number_of_unique_lists_v3():
a = [[1, 2, 3], [1, 2], [3, 4], [1, 2, 3]]
s = List()
for x in a:
if not x in s:
s.append(x)
number = len(s)
return number
print(number_of_unique_lists())
>>> 3
BUT this does not work for me since the list a is created slightly differently in my function, similar as shown in a minimal example below.
from numba.typed import List
#nb.njit
def number_of_unique_lists():
a = [[0] for _ in range(4)]
a[0] = [1, 2, 3]
a[1] = [1, 2]
a[2] = [3, 4]
a[3] = [1, 2, 3]
s = List()
for x in a:
if not x in s:
s.append(x)
number = len(s)
return number
Now I get an error which I don't understand...
Here is one working solution using numba.typed.List() objects
import numba as nb
from numba.typed import List
#nb.njit
def number_of_unique_lists(a):
s = List()
for x in a:
if not x in s:
s.append(x)
number = len(s)
return number
a = [[1,2,3],[1,2],[3,4],[1,2,3]]
typed_a = List()
for x in a:
s = List()
for y in x:
s.append(y)
typed_a.append(s)
print(number_of_unique_lists(typed_a))
>>> 3
Related
I have two input lists as following:
x_values = [1,2,3]
y_values = [1,2,3]
Is there a quick way to create a list of dictionaries from these two lists, like following:
points = [{x=1, y=1},{x=2, y=2},{x=3, y=3}]
Thanks in advance.
If I understood the question this should help:
>>> x_values = [1, 2, 3]
>>> y_values = [1, 2, 3]
>>> points = [{"x":i, "y":j} for i, j in zip(x_values, y_values)]
>>> points
[{'y': 1, 'x': 1}, {'y': 2, 'x': 2}, {'y': 3, 'x': 3}]
There could be a more Pythonic way to do this, but one straight forward approach could be:
x_values = [1,2,3]
y_values = [1,2,3]
points = []
i = 0
while i < len(x_values):
new_dict = {}
new_dict['y'] = y_values[i]
new_dict['x'] = x_values[i]
points.append(new_dict)
i += 1
This may at least get you going.
I am trying to match two lists, but I want to pick up the repeat matches too. I can't use set because that would only give me {3} in my second example below.
a = [1,2,3,4]
b = [3,3,4,5]
return [3,4]
a = [1,2,3,3]
b = [3,3,4,5]
return [3,3]
You can use list comprehesion to check and return every item in a if it exists in b like below:
[item for item in a if item in b]
If you want only the elements that are in both a and b (to cover the cases mentioned by #kabanus in the comment), you can use the following:
[item for item in set(a) for i in range(min(a.count(item), b.count(item)))]
Output:
>>> a = [1, 2, 3, 4]
>>> b = [3, 3, 4, 5]
>>> [item for item in set(a) for i in range(min(a.count(item), b.count(item)))]
[3, 4]
>>>
>>> a = [1, 2, 3, 3]
>>> b = [3, 3, 4, 5]
>>> [item for item in set(a) for i in range(min(a.count(item), b.count(item)))]
[3, 3]
>>>
>>> a = [3, 3, 4]
>>> b = [4, 4, 3]
>>> [item for item in set(a) for i in range(min(a.count(item), b.count(item)))]
[3, 4]
Try something like (if order doesn't matter), Python 2:
from collections import Counter
a = [1,2,3,4]
b = [3,3,4,5]
ca=Counter(a)
cb=Counter(b)
print sum([[x]*min(ca[x],cb[x]) for x in set(a)],[])
This should return the list of all repeating matches the number of time they repeat, with no particular ordering beyond grouping together same elements. The output for the above example is:
[3,4]
I'm assuming you missed 4. The other example you have yields what you posted:
[3,3]
If I have an input like this (1, 2, 3, 4, 5, 6)
The output has to be ... [[1, 2], [3, 4], [5, 6]].
I know how to deal with if it's one element but not two.
x=[]
for number in numbers:
x.append([number])
I'll appreciate your any help!
Something like this would work:
out = []
lst = (1,2,3,4,5,6,7,8,9,10)
for x in range(len(lst)):
if x % 2 == 0:
out.append([lst[x], lst[x+1]])
else:
continue
To use this, just set lst equal to whatever list of numbers you want. The final product is stored in out.
There is a shorter way of doing what you want:
result = []
L = (1,2,3,4,5,6,7,8,9,10)
result = [[L[i], L[i + 1]] for i in range(0, len(L) - 1, 2)]
print(result)
You can use something like this. This solution also works for list of odd length
def func(lst):
res = []
# Go through every 2nd value | 0, 2, 4, ...
for i in range(0, len(lst), 2):
# Append a slice of the list, + 2 to include the next value
res.append(lst[i : i + 2])
return res
# Output
>>> lst = [1, 2, 3, 4, 5, 6]
>>> func(lst)
[[1, 2], [3, 4], [5, 6]]
>>> lst2 = [1, 2, 3, 4, 5, 6, 7]
>>> func(lst2)
[[1, 2], [3, 4], [5, 6], [7]]
List comprehension solution
def func(lst):
return [lst[i:i+2] for i in range(0, len(lst), 2)]
Slicing is better in this case as you don't have to account for IndexError allowing it to work for odd length as well.
If you want you can also add another parameter to let you specify the desired number of inner elements.
def func(lst, size = 2): # default of 2 it none specified
return [lst[i:i+size] for i in range(0, len(lst), size)]
There's a few hurdles in this problem. You want to iterate through the list without going past the end of the list and you need to deal with the case that list has an odd length. Here's one solution that works:
def foo(lst):
result = [[x,y] for [x,y] in zip(lst[0::2], lst[1::2])]
return result
In case this seems convoluted, let's break the code down.
Index slicing:
lst[0::2] iterates through lst by starting at the 0th element and proceeds in increments of 2. Similarly lst[1::2] iterates through starting at the 1st element (colloquially the second element) and continues in increments of 2.
Example:
>>> lst = (1,2,3,4,5,6,7)
>>> print(lst[0::2])
(1,3,5,7)
>>> print(lst[1::2])
(2,4,6)
zip: zip() takes two lists (or any iterable object for that matter) and returns a list containing tuples. Example:
>>> lst1 = (10,20,30, 40)
>>> lst2 = (15,25,35)
>>> prit(zip(lst1, lst2))
[(10,15), (20,25), (30,35)]
Notice that zip(lst1, lst2) has the nice property that if one of it's arguments is longer than the other, zip() stops zipping whenever the shortest iterable is out of items.
List comprehension: python allows iteration quite generally. Consider the statement:
>>> [[x,y] for [x,y] in zip(lst1,lst2)]
The interior bit "for [x,y] in zip(lst1,lst2)" says "iterate through all pairs of values in zip, and give their values to x and y". In the rest of the statement
"[[x,y] for [x,y] ...]", it says "for each set of values x and y takes on, make a list [x,y] to be stored in a larger list". Once this statement executes, you have a list of lists, where the interior lists are all possible pairs for zip(lst1,lst2)
Very Clear solution:
l = (1, 2, 3, 4, 5, 6)
l = iter(l)
w = []
for i in l:
sub = []
sub.append(i)
sub.append(next(l))
w.append(sub)
print w
Is there a way to do this with list comprehension?
for i in range(0, len(x)):
if i == 0:
sum = x[i]
else:
sum = sum * x[i]
I've tried this:
[total for i in x if i == 0 total = x[i] else total = total * x[i]]
and this:
[total = x[i] if i == 0 else total = total * x[i] for i in x]
I saw that there is a way to do it with enumerate but I was wondering if there is a way to do it in one line just using list comprehension. I'm not trying to solve a problem, I'm just curious.
I think what you need is reduce, but not list comprehension.
from operator import mul
s = [1, 2, 3]
print reduce(mul, s, 1)
Or using list comprehension:
class Mul(object):
def __init__(self):
self.product = 1
def __call__(self, x):
self.product *= x
return self.product
s = [1, 2, 3, 4, 5]
m = Mul()
[m(x) for x in s]
I'm gonna prefix this with "you do not want to do this". No really. But if you did...
# whatever your input is
x = [1, 2, 3, 4, 5]
# set the initial total to 1, and wrap it in a list so we can modify it in an expression
total = [1]
# did I mention you shouldn't do this?
[total.__setitem__(0, xi * total.__getitem__(0)) for xi in x]
print total[0]
120
I have a nested sequence that I want to flatten into a single list of values.
Please try this general solution:
Write a recursive generator function involving a yield from
statement. For example:
from collections import Iterable
def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x, ignore_types)
else:
yield x
items = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
print(x)
I'd go with recursion but split in a balanced way.
def flatten(lst):
n = len(lst)
if n == 0:
return lst
elif n == 1:
item = lst[0]
try:
return flatten(list(item))
except TypeError:
return [item]
else:
k = n // 2
return flatten(lst[:k]) + flatten(lst[k:])
Demo
items = [1, 2, [3, 4, [5, 6], 7], 8]
flatten(items)
[1, 2, 3, 4, 5, 6, 7, 8]