How to make a list start-end connected? - python

I have this list:
l = [0, 1, 2]
and obviously l[0] = 0, l[1] = 1, l[2] = 2,
but I want l[3] to be = to 0, l[4] = 1, l[5] = 2 and so on...

you can use the modulus operator to cycle through the elements of the list.
l[index % 3]
In general:
lst = [0, 1, 2]
lst[index % len(lst)]

Depending on what you're trying to do, you can "multiply" a list to create a longer, repeating list of the original. Alternatively, you can create an iterator that just yields the same sequence of numbers indefinitely:
>>> numbers = [0, 1, 2] * 5
>>> numbers
[0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2]
>>> from itertools import cycle
>>> number_iter = cycle([0, 1, 2])
>>> next(number_iter)
0
>>> next(number_iter)
1
>>> next(number_iter)
2
>>> next(number_iter)
0
>>> next(number_iter)
1
>>> next(number_iter)
2
>>>

Related

Generate a list based on the index of another list

I have a list:
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
I want to change this to:
result = [[0, 0], [1, 2], [4, 5]]
How to generate:
array: [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
map: 0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
# start to end, generate the result like `[int(start), int(end)]`
combine them:[[0, 0], [1, 2], [4, 5]]
0 and 1 wouldn't appear in pairs. So the numbers in result must be an integer.
What I have tried:
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
output = [[]]
for pre, next_ in zip(hash_table, hash_table[1:]):
output[-1].append(pre)
if {next_, pre} == {0, 1}:
output.append([])
output[-1].append(hash_table[-1])
# the output is [[1], [0], [1, 1, 1], [0, 0, 0], [1, 1, 1]]
start = index = 0
result = []
while index < len(output):
# output[index]
if output[0] != 0:
res.append([start, math.ceil(len(output[index]))])
# I don't know how to handle the list "output".
# I couldn't know it. My mind has gone blank
start += len(output[index])/2
Any good ideas? I thought I made it too complicated.
You can use itertools.groupby to group the 0s and 1s:
import itertools
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
result = []
cur_ind = 0
for (val, vals) in itertools.groupby(hash_table):
vals = list(vals) # itertools doesn't make it a list by default
old_ind = cur_ind
cur_ind += len(vals)
if val == 0:
continue
result.append([old_ind // 2, (cur_ind - 1) // 2])
print(result)
Essentially, itertools.groupby will give an iterator of [(1, [1]), (0, [0]), (1, [1, 1, 1]), (0, [0, 0, 0]), (1, [1, 1, 1])] (more or less). We can iterate through this iterator and keep track if the index we're on by adding the length of the sublist to the current index. If the value is 1, then we have a run of ones so we append it to the results. The old_ind // 2 is integer division and is equivalent to int(old_ind / 2).
You could use groupby from itertools library:
import itertools
hash_table = [1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1]
s = "".join(map(str, hash_table)) # s = "10111000111"
gs = [(i, list(g)) for i, g in itertools.groupby(s)]
idx, result = 0, []
for i, g in gs: # i can be '1' or '0' (i.e, if the group consist in 1's or 0's)
if i == '1':
result.append([idx/2, (idx + len(g) - 1)/2])
idx += len(g)
return result

Add a number to list in a specified index range

Input
l = [0, 0, 1, 2, 3]
I want to add 1 to index range from 2 to 3
so output should be
l = [0, 0, 2, 3, 3]
l[2:3] = l[2:3] + 1
The easiest way would be to use numpy, it's quite optimized and uses C/C++ loops under the hood, so it's blazingly fast:
>>> import numpy as np
>>> a = [0, 0, 1, 2, 3]
>>> b = np.array(a)
>>> b[2:4] += 1
>>> b
array([0, 0, 2, 3, 3])
>>>
You can try this:
for i in range(2, 4):
l[i] += 1
A possible solution can make use of list-comprehension:
l[2:4] = [x+1 for x in l[2:4]]
For a hilariously overblown solution:
from operator import add
l = [0, 0, 1, 2, 3]
deltas = [0, 0, 1, 1, 1]
result = list(map(add, l, deltas))
note that this does not modify l, but creates a new list in result

In python randomly concatenating two arrays until limit length is met

Say i have two arrays:
a = [1, 1, 1] and
b = [0, 0]
I want to concatenate these randomly in a seperate variable c, until i reach some desired length of c. So something like:
N = 10
c = random_concatenating((a, b), N)
[1, 1, 1, 0, 0, 1, 1, 1, 0, 0]
A verbose version:
import random
a = [1, 1, 1]
b = [0, 0]
N = 10
def random_concatenating(iterable, n):
rv = []
l = [*iterable]
print(l)
while len(rv) < n:
rv.extend(random.choice(l))
return rv[:n]
c = random_concatenating((a, b), N)
print(c)
Prints (for example):
[1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
You can use itertools.cycle to repeat the lists as many times as you need then slice them to the needed list
>>> from itertools import cycle, islice
>>> a = [1, 1, 1]
>>> b = [0, 0]
>>> N = 10
>>> list(islice(cycle(a+b), N))
[1, 1, 1, 0, 0, 1, 1, 1, 0, 0]
This is one approach. Using random.choice
import random
a = [1, 1, 1]
b = [0, 0]
N = 10
foo = a + b
c = []
for i in range(N):
c.append(random.choice(foo))
print(c)
Output:
[0, 1, 1, 1, 1, 0, 1, 1, 1, 1]
One-line
c = [random.choice(foo) for i in range(N)]

Add element into list at even indexes [duplicate]

This question already has answers here:
python: most elegant way to intersperse a list with an element
(15 answers)
Closed 6 years ago.
I have a list like
[1, 2, 3, 4, 5]
and I want to add zeroes at odd indexes:
[1, 0, 2, 0, 3, 0, 4, 0, 5]
My first thought was to create a list with zeroes and replace them with the values from the original list.
listOfZeros = [0] * (2*len(list)-1)
j = 0
for i in range(0, len(listOfZeros)):
if (i%2 == 0):
listOfZeros[i] = h_temp[j]
j += 1
This actually works, but I do dislike for loops and adding another counter j. Isn't there a better way by using slicing?
You can use insert(). Looking at your output, assuming you are not counting index 0 as even.
a = [1,2,3,4,5]
for x in range(len(a)):
a.insert(2*x+1, 0)
one way is by using zip:
a = [1, 2, 3, 4, 5]
d = [x for t in zip (a, [0] * len(a)) for x in t][:-1]
When you use zip, you create list of tuples.
a = [1,2,3,4,5]
b = [0,0,0,0,0]
c = zip(a,b)
#zip (a,b) creates [(1,0),(2,0),(3,0),(4,0),(5,0)]
Then you loop over the set of tuples to arrange them into list:
d = [x for t in c for x in t] #creates [1,0,2,0,3,0,4,0,5,0]
and cut the last element (since you end with 5)
[x for t in c for x in t][:-1] #take out the last 0
#resulting in [1,0,2,0,3,0,4,0,5]
then you are done.
You can do it with a generator:
def zero_on_odd(mylist):
for i in mylist:
yield i
yield 0
a = [1, 2, 3]
with_zeros = list(zero_on_odd(a))[:-1]
If you want to go functional...
from itertools import chain, repeat
_list = [1,2,3,4,5]
list(chain(*zip(_list, repeat(0))))[:-1]
# [1, 0, 2, 0, 3, 0, 4, 0, 5]
If you want to be silly...
[int(i) for i in '0'.join(str(i) for i in _list)]
# still [1, 0, 2, 0, 3, 0, 4, 0, 5]
Or, if you want to be functional AND silly...
map(int, '0'.join(map(str, _list)))
# really, it's still [1, 0, 2, 0, 3, 0, 4, 0, 5]
# except in Python 3.X, there it's a map object...
But, you should probably opt for one of the custom generator solutions.
For the fun of it, here is an itertools solution:
from itertools import islice, chain
data = [1,2,3,4,5]
print list(islice(chain.from_iterable((x, 0) for x in data), 0, 2 * len(data)-1))
Giving:
[1, 0, 2, 0, 3, 0, 4, 0, 5]
Another zip way:
>>> li
[1, 2, 3, 4, 5]
>>> [e for t in zip(li,[0]*(len(li)-1)) for e in t]+[li[-1]]
[1, 0, 2, 0, 3, 0, 4, 0, 5]
You can also use range and slice assignment:
>>> li=[1,2,3,4,5]
>>> for i in range(1,len(li)+len(li)-1, 2): li[i:i]=[0]
...
>>> li
[1, 0, 2, 0, 3, 0, 4, 0, 5]
And, a list comprehension:
>>> [li[i/2] if not i%2 else 0 for i in range(len(li)*2-1)]
[1, 0, 2, 0, 3, 0, 4, 0, 5]
A hacky way:
>>> ls1 = [1, 2, 3, 4, 5]
>>> ls2 = []
>>> list(ls2.extend([n, 0]) for n in ls1)
[None, None, None, None, None]
>>> ls2
[1, 0, 2, 0, 3, 0, 4, 0, 5, 0]

How can I repeat elements in place in an array in Python?

How can I repeat elements in place in an array in Python?
Or similarly, something more simple than this:
drange = [];
for i in xrange(j):
drange.append(i);
drange.append(i);
It should produce: [0, 0, 1, 1, 2, 2, ... j-1, j-1]
>>> j = 3
>>> drange = []
>>> for i in xrange(j):
... drange.extend([i]*2)
...
>>> drange
[0, 0, 1, 1, 2, 2]
or as a list comprehension
>>> drange = [i for i in xrange(j) for k in range(2)]
>>> drange
[0, 0, 1, 1, 2, 2]
In some cases this method can also be appropriate
>>> drange = [i//2 for i in xrange(j*2)]
>>> drange
[0, 0, 1, 1, 2, 2]
An answer using numpy
>>> import numpy as np
>>> j = 3
>>> np.repeat(np.array(xrange(j)), 2)
array([0, 0, 1, 1, 2, 2])
Use list comprehension then flatten the list:
>>> sum([ [i]*2 for i in xrange(5)],[])
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
Here is a two-line alternative.
base= [2*[i] for i in range(5)]
drange = [item for x in base for item in x]

Categories