python - make a list with repetitive elements - python

I know if I want to create a list like this:
[0 1 2 0 1 2 0 1 2 0 1 2]
I can use this command:
range(3) * 4
Is there a similar way to create a list like this:
[0 0 0 0 1 1 1 1 2 2 2 2]
I mean a way without loops

Integer division can help:
[x/4 for x in range(12)]
Same thing through map:
map(lambda x: x/4, range(12))
In python 3 integer division is done with //.
Beware that multiplication of a list will likely lead to a result you probably don't expect.

Yes, you can.
>>> [e for e in range(3) for _ in [0]*4]
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]

itertools module is always an option:
>>> from itertools import chain, repeat
>>> list(chain(repeat(0, 4), repeat(1, 4), repeat(2, 4)))
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
More general way is:
def done(group_count, repeat_count):
return list(chain(*map(lambda i: repeat(i, repeat_count),
range(group_count))))
>>> done(3, 4)
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]

Without any explicit "for" :)
>>> list(chain(*zip(*([range(5)] * 5))))
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4]

What about this:
>>> sum([ [x]*4 for x in range(5)],[])
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]
>>>
or
>>> reduce(lambda x,y: x+y, [ [x]*4 for x in range(5)])
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4]
>>>

If you can't use a loop in your current method, create one in an other?
range(0,1)*4 + range(1,2)*4 + range(2,3)*4

Related

how to sort in array index to index

Hey everyone how can I sort array index to index.
So I have code here
a = [0, 1, 2, 3, 4, 4, 3, 2, 1, 0, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4]
how can i sort to?
[0, 4, 1, 3, 2, 2, 3, 1, 4, 0, 4, 0, 3, 1, 2, 2, 1, 3, 0, 4]
this is my idea
I could be wrong, but it sounds like you would like to return a list that is sorted like this:
[first_item, last_item, second_item, second_to_last_item, third_item, third_to_last_item,...]
I don't know of a one-line way to do that, but here's one way you could do it:
import numpy as np
a = [0, 1, 2, 3, 7] # length of list is an odd number
# create indexes that are all positive
index_values = np.repeat(np.arange(0, len(a)//2 + 1), 2) # [0,0,1,1,.....]
# make every other one negative
index_values[::2] *= -1 #[-0, 0, -1, 1, ....]
# return a[i]
[a[i] for i in index_values[1:(len(a)+1)]]
### Output: [0, 7, 1, 3, 2]
It also works for lists with even length:
a = [0, 1, 2, 3, 7, 5] # list length is an even number
index_values = np.repeat(np.arange(0, len(a)//2 + 1), 2) # [0,0,1,1,.....]
index_values[::2] *= -1 #[-0, 0, -1, 1, ....]
[a[i] for i in index_values[1:(len(a)+1)]]
### Output: [0, 5, 1, 7, 2, 3]
Here’s an almost one liner (based on #Callin’s sort method) for those that want one and that can’t/don’t want to use pandas:
from itertools import zip_longest
def custom_sort(a):
half = len(a)//2
return [n for fl in zip_longest(a[:half], a[:half-1:-1]) for n in fl if n is not None])
Examples:
custom_sort([0, 1, 2, 3, 7])
#[0, 7, 1, 3, 2]
custom_sort([0, 1, 2, 3, 7, 5])
#[0, 5, 1, 7, 2, 3]
This can be done in one line, although you’d be repeating the math to find the halfway point
[n for x in zip_longest(a[:len(a)//2], a[:(len(a)//2)-1:-1]) for n in x if n is not None]
Sometimes we want to sort in place, that is without creating a new list. Here is what I came up with
l=[1,2,3,4,5,6,7]
for i in range(1, len(l), 2):
l.insert(i, l.pop())

Generating all lists that satisfy certain constraints in Python

I would like to generate the following lists in Python:
[1, 1, 1, 2, 2]
[1, 1, 2, 1, 2]
... etc
[2, 1, 2, 1, 1]
[2, 2, 1, 1, 1]
There are always two "2"s and three "1"s in any list.
My intuition suggests that I will need to use the itertools module to do this. However, I am not sure where to begin, though I have read the documentation and looked at examples. Any suggestions?
You can notice that the number of such lists is equal to the number of ways to place two "2"s in a sequence of length 5. This suggests the following solution:
n = 5 # total length
n2 = 2 # number of "2"s
for idx in itertools.combinations( xrange(n), n2 ):
print [ 2 if i in idx else 1 for i in xrange(n) ]
It's easy to see that the answer using permutations is iterating over n! solutions, while my solution iterates over n!/( (n-n2)! * n2!). For example if the input list is [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2], the solution using permutations is ~90,000,000 times slower (10! * 4!)
You can use itertools.permutations and set (to eliminate duplicates):
>>> from itertools import permutations
>>> for combo in set(permutations([1, 1, 1, 2, 2])):
... print(list(combo))
...
[1, 2, 1, 1, 2]
[2, 1, 1, 1, 2]
[2, 1, 2, 1, 1]
[2, 1, 1, 2, 1]
[1, 1, 2, 1, 2]
[1, 1, 1, 2, 2]
[1, 2, 1, 2, 1]
[1, 1, 2, 2, 1]
[1, 2, 2, 1, 1]
[2, 2, 1, 1, 1]
>>>
If the combinations need to be in order, then you can use sorted:
>>> for combo in sorted(set(permutations([1, 1, 1, 2, 2]))):
... print(list(combo))
...
[1, 1, 1, 2, 2]
[1, 1, 2, 1, 2]
[1, 1, 2, 2, 1]
[1, 2, 1, 1, 2]
[1, 2, 1, 2, 1]
[1, 2, 2, 1, 1]
[2, 1, 1, 1, 2]
[2, 1, 1, 2, 1]
[2, 1, 2, 1, 1]
[2, 2, 1, 1, 1]
>>>

List of repeating integers

What is the most pythonic way to create a list of given size N= l*k where l is the number of different symbols (integers for simplicity) and k is the subsequence length like this:
N=12, l=4, k=3
[ 0,0,0, 1,1,1, 2,2,2, 3,3,3 ]
or this for example N=15 l=3, k=5:
[ 0,0,0,0,0, 1,1,1,1,1, 2,2,2,2,2 ]
this function should be called very often so speed is desirable.
Using numpy you can do this:
In [23]: import numpy as np
In [26]: a=np.arange(3).repeat(5)
In [27]: a
Out[27]: array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2])
or python builtin:
In [29]: [l for l in range(3) for k in range(5)]
Out[29]: [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2]
>>> l=3
>>> k=5
>>> [e for i in range(l) for e in [i]*k]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2]
I like this lazy version (it returns an iterator, not a list, and you can generate values out of it when you want).
l, k = 3, 5
itertools.chain.from_iterable(itertools.repeat(i, k) for i in xrange(l))
It outputs this:
list(itertools.chain.from_iterable(itertools.repeat(i, k) for i in xrange(l)))
# [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2]
Perhaps with itertools.repeat and itertools.chain.from_iterable?
>>> from itertools.import repeat, chain
>>> k = 3
>>> l = 4
>>> list(chain.from_iterable(list(repeat(x, k)) for x in xrange(l))
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]
>>> sum([[x]*3 for x in xrange(4)], [])
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3]
Putting it into a function:
def combine(l, k):
return sum([[x]*k for x in xrange(l)], [])
import itertools
l = 3
k = 5
print(list(itertools.chain(*[[i] * k for i in range(l)])))
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2]

Python change list elements in a for loop

Let's say I have a list of 5 elements x=[a,b,c,d,e] and I want to run a for loop that prints all lists where two of the entries are 1 less than the corresponding entries in the original list.
What is a simple way to do this in Python? Thanks in advance.
Edit: if x=[4,5,6,7,8] I want:
[3,4,6,7,8], [3,5,5,7,8], [3,5,6,6,8] etc.
Something like this:
>>> from itertools import combinations
>>> lis = [0,1,2,3,4]
>>> for x,y in combinations(range(len(lis)),2):
l = lis[:]
l[x] -= 1
l[y] -= 1
print l
...
[-1, 0, 2, 3, 4]
[-1, 1, 1, 3, 4]
[-1, 1, 2, 2, 4]
[-1, 1, 2, 3, 3]
[0, 0, 1, 3, 4]
[0, 0, 2, 2, 4]
[0, 0, 2, 3, 3]
[0, 1, 1, 2, 4]
[0, 1, 1, 3, 3]
[0, 1, 2, 2, 3]
Shorter version:
for x,y in combinations(range(len(lis)),2):
print [item - 1 if i in (x,y) else item for i,item in enumerate(lis)]
...
[-1, 0, 2, 3, 4]
[-1, 1, 1, 3, 4]
[-1, 1, 2, 2, 4]
[-1, 1, 2, 3, 3]
[0, 0, 1, 3, 4]
[0, 0, 2, 2, 4]
[0, 0, 2, 3, 3]
[0, 1, 1, 2, 4]
[0, 1, 1, 3, 3]
[0, 1, 2, 2, 3]
from itertools import combinations
a = [1,2,3,4]
for combination in combinations(range(len(a)),r=2):
print [c-(1 if i in combination else 0) for i,c in enumerate(a)]

python range() with duplicates?

Everybody knows that a list of numbers can be obtained with range like this;:
>>> list(range(5))
[0, 1, 2, 3, 4]
If you want, say, 3 copies of each number you could use:
>>> list(range(5)) * 3
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
But is there an easy way using range to repeat copies like this instead?
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
Examples:
sorted(list(range(5)) * 3) # has unnecessary n * log(n) complexity
[x//3 for x in range(3*5)] # O(n), but division seems unnecessarily complicated
You can do:
>>> [i for i in range(5) for _ in range(3)]
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
the range(3) part should be replaced with your number of repetitions...
BTW, you should use generators
Just to make it clearer, the _ is a variable name for something you don't care about (any name is allowed).
This list comprehension uses nested for loops and are just like that:
for i in range(5):
for j in range(3):
#your code here
Try this:
itertools.chain.from_iterable(itertools.repeat(x, 3) for x in range(5))
from itertools import chain, izip
list(chain(*izip(*[xrange(5)]*3)))
Gives
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
Leave off the list and you have a generator.
EDIT: or even better (leaves out a function call to izip):
list(chain(*([x]*3 for x in xrange(5))))
There is a very simple way to do this with a help from numpy. Example:
>>> import numpy as np
>>> np.arange(5*3) // 3
array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])
With range you can do the following:
>>> list(map(lambda x: x // 3, range(5*3)))
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
Remembering that // performs a strict integer division.
>>> from itertools import chain, izip, tee
>>> list(chain.from_iterable(izip(*tee(range(5), 3))))
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
A cool iterator using another approach:
>>> from collections import Counter
>>> Counter(range(5) * 3).elements()
I like to Keep It Simple :)
>>> sorted(list(range(5)) * 3)
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]
import itertools
[x for tupl in itertools.izip(*itertools.tee(range(0,5),3)) for x in tupl]
Or:
[x for tupl in zip(range(0,5), range(0,5), range(0,5)) for x in tupl]

Categories

Resources