None, None, etc in a list comprehension printing - list

can somebody explain me that?:
a = []
[a.append(i) for i in range(0, 4)]
print(a) # output : [0, 1, 2, 3]
a = []
print([a.append(i) for i in range(0, 4)]) # output : [None, None, None, None]
a = []
for i in range(0, 4): a.append(i)
print(a) # output : [0, 1, 2, 3]
Thanks!!

list.append() modifies list in place and returns None, so if you use a REPL you can see this:
>>> a = []
>>> [a.append(i) for i in range(4)] # didn't assign to a variable, so prints result in REPL
[None, None, None, None] # append returns None so get 4 of them.
>>> print(a) # append modifies the list, so it has the value.
[0, 1, 2, 3]
You should not use in-place actions in a list comprehension, just use:
a = [x for x in range(4)]
or
a = list(range(4))

Related

Unique lists in nested list in numba

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

Checking for duplicates in a list Python

dataset:
raw_data = [[1, John, 23, 32], [1, Jane, 10, 20], [1, Max, 90, 70], [2, Harry, 32, 56]]
list = []
for i in raw_data:
if i[0] in list:
x = i[0] + 0.1
list.append(x)
else:
list.append(i[0])
I would actually like to obtain list = [1, 1.1, 1.2, 2]
However, my code is giving my list = [1, 1.1, 1.1, 2]
How can I run another loop in my list to add a 0.1 to a duplicated number?
You could use a dictionary to cache the increments:
cache = {}
result = []
for i in raw_data:
if i[0] in cache:
cache[i[0]] += 0.1
else:
cache[i[0]] = 1
result.append(cache[i[0]])
EDIT:
Using a defaultdict would save the condition inside the loop. Whether or not it's more elegant is in the eye of the beholder, though:
from collections import defaultdict
cache = defaultdict(lambda : 0.9)
result = []
for i in raw_data:
cache[i[0]] += 0.1
result.append(cache[i[0]])

Python - get repeat matches in two lists

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]

python3.2)append two element in a list(lists in a list)

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

how to get the list of the lists?

I have a problem like that:
list = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
I want to get a new list like that
new_list['a1','b1','c1','d1']
I do like this:
lst = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
for item in lst:
print(item)
result is:
a1
['b1', 2]
['c1', 2, 3]
['d1', 2, 3, 4]
But I want the first element of each result
The best answer is like this :
my_list = list()
lst = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
for element in lst:
if type(element)==type('string'):
my_list.append(element)
else:
my_list.append(element[0])
print(my_list)
Thank you!
Do it as below:
>>> my_list = list()
>>> lst = ['a1',['b1',2],['c1',2,3],['d1',2,3,4]]
>>> for element in lst:
if type(element)==type('string'):
my_list.append(element)
else:
my_list.append(element[0])
It will produce:
>>> my_list
['a1', 'b1', 'c1', 'd1']
>>>
As you see above, first I created a list (named my_list) and then checked each elements of your list. If the element was a string, I added it to my_list and otherwise (i.e. it is a list) I added the first element of it to my_list.
I would do
res = []
for x in the_list:
if x is Array:
res.append(x[0])
else:
res.append(x)