How to duplicate a specific value in a list/array? - python

Any advice on how to repeat a certain value in an array in Python?
For instance, I want to repeat only 2 in array_a:
array_a = [1, 2, 1, 2, 1, 1, 2]
Wanted outcome is: I repeat each 2 and leave the 1:
array_a = [1, 2, 2, 1, 2, 2, 1, 1, 2, 2] # only the `2` should be repeated
I tried numpy and I could duplicate the entire array but not a certain value.

If you're interested in a numpy solution, you can repeat an array on itself using np.repeat.
>>> import numpy as np
>>> np.repeat(array_a, array_a)
array([1, 2, 2, 1, 2, 2, 1, 1, 2, 2])
This works only if you haves 1s and 2s in your data. For a generic solution, consider
>>> n_repeats = 2
>>> temp = np.where(np.array(array_a) == 2, n_repeats, 1)
>>> np.repeat(array_a, temp)
array([1, 2, 2, 1, 2, 2, 1, 1, 2, 2])

May be you can use dictionary to each unique element and number of times it needs to be repeated. Then using list comprehension to create array:
array_a = [1,2,1,2,1,1,2]
repeat_times = {1:1, 2:2} # 1 is 1 time and 2 is repeated two times
result = [i for i in array_a for j in range(repeat_times[i])]
print(result)
Output:
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]

This seems a good use-case for a generator:
>>> def repeater(iterable, repeat_map):
... for value in iterable:
... for i in range(repeat_map.get(value, 1)):
... yield value
...
>>> array_a = [1,2,1,2,1,1,2]
>>> list(repeater(array_a, repeat_map={2: 2}))
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]

If you convert this to a list, you can loop through it, and if it matches your criteria, add an extra version. For example:
a = [1,2,1,2,1,1,2]
long_a = []
for x in a:
long_a.append(x)
if x == 2:
long_a.append(x)

loop over the array (a 'list' in python)
find the the number
get the position of the matched number in the array
insert another number after each matched position
https://docs.python.org/3/reference/compound_stmts.html#for
https://docs.python.org/2/tutorial/datastructures.html#more-on-lists

An attempt using comprehensions.
array = [1, 2, 1, 2, 1, 1, 2]
element_to_repeat = 2
result = [
repeats_element
for repeats in
((element,)*2 if element == element_to_repeat else (element,) for element in array)
for repeats_element in repeats
]
It basically spits out tuples, "repeats", which contain the element once if it's not the element to repeat, or twice if it's the element to repeat. Then all of the elements of these "repeats" tuples are flattened into the answer.

Using a generator.
array = [1, 2, 1, 2, 1, 1, 2]
element_to_repeat = 2
def add_repeats(array, element_to_repeat):
for element in array:
if element == element_to_repeat:
yield element
yield element
else:
yield element
result = list(add_repeats(array, element_to_repeat))

Here is a handy one-liner using itertools and list comprehension with if and else in it. First it makes a nested list (to have the ability to repeat items on a certain position) and then it will simply flatten it at the end using .chain()-method:
from itertools import chain
array_a = [1, 2, 1, 2, 1, 1, 2]
list(chain.from_iterable([[item, item] if item == 2 else [item] for item in array_a]))
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2] # output
The specific value to double is inside the if-statement. Using multipliers (instead of [item, item]) and a variable (instead of 2) would make this easily more generic, see this for example:
from itertools import chain
def repeat_certain_value(array, val, n):
return list(chain.from_iterable(([i] * n if i == val else [i] for i in array)))
repeat_certain_value([1, 2, 1, 2, 1, 1, 2], 2, 2)
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2] # output
repeat_certain_value([0, -3, 1], -3, 5)
[0, -3, -3, -3, -3, -3, 1] # output
While this approach is a handy one-liner using builtin libraries, the approach from coldspeed is faster:
%timeit for x in range(1000): repeat_certain_value([1, 1, 1, 2, 2, 2, 3, 3, 3] * 100, 2, 2)
10 loops, best of 3: 165 ms per loop
%timeit for x in range(1000): coldspeeds_solution([1, 1, 1, 2, 2, 2, 3, 3, 3] * 100, 2, 2)
10 loops, best of 3: 100 ms per loop

Can try a list comprehension and create a flat function:
array_a = [1, 2, 1, 2, 1, 1, 2]
def flat(l):
newl=[]
for i in l:
if isinstance(i,list):
newl.extend(i)
else:
newl.append(i)
return newl
print(flat([[i]*2 if i==2 else i for i in array_a]))
Output:
[1, 2, 2, 1, 2, 2, 1, 1, 2, 2]

Related

How can I sum the first index and last index until the len(list) = 2?

Im trying to get a percentaje from a list of numbers, but it is a little different than the usual methods.
Bassically I need to sum the first index of the list with the last index of the same list. I want the script to do this repeatedly until the lenght of the list equals 2.
Something like this:
list = [1, 1, 2, 1, 1, 1, 1, 1, 1, 1]
list = [2, 2, 3, 2, 2]
list = [4, 4, 3]
list = [7, 4] #here the lenght = 2, so it stops.
final_list = [7, 4]
percentaje = f"%{final_list[0]}{final_list[1]}"
#OUTPUT
#"%74"
Can someone help me to do this? Im not so good with loops :(
This?
L = [1, 1, 2, 1, 1, 1, 1, 1, 1, 1]
while len(L) > 2:
new_L = [L[i]+L[len(L)-1-i] for i in range(len(L)//2)]
if len(L)%2:
new_L.append(L[len(L)//2]) # add middle term alone if any
L = new_L
print(f"%{L[0]}{L[1]}")
list1 = [1, 1, 2, 1, 1, 1, 1, 1, 1, 1]
while len(list1)!=2:
for i in range (0, int(len(list1)/2)):
list1[i] = list1[i] + list1[len(list1)-1]
list1 = list1[:-1]
print(list1)
output:
[7, 4]

After using combinations with replacement, how to remove tuples with combinations that I don't want

I'm trying to get a list of lists (or tuples) which follows a pattern something like this:
[1,1,1,2]
[1,1,2,2]
[1,2,2,2]
[1,2,2,3]
[1,2,3,3]
[1,2,3,4]
Using itertools.combinations_with_replacement I've gotten close, but I end up with lists which jump values for example:
[1,1,1,3]
or
[2,2,2,3]
I don't want this. I always want to start at 1, and increase until the list is filled, and then increase to the next value.
If I'm using itertools, then is there a way to remove the lists that I don't want?
Instead of using combinations, I would generate the pattern directly.
Create a list of 1's with the desired length and iterate backward, changing the list accordingly.
def generate_increment(n):
lst = [1] * n
result = []
for k in range(n-1):
lst[-1] += 1
result.append(lst[:])
for i in range(len(lst)-2, k, -1):
a, b = lst[i], lst[i+1]
if a != b:
lst[i] = b
result.append(lst[:])
return result
>>print(*generate_increment(4), sep='\n')
[1, 1, 1, 2]
[1, 1, 2, 2]
[1, 2, 2, 2]
[1, 2, 2, 3]
[1, 2, 3, 3]
[1, 2, 3, 4]
It feels like validating the results of combinations will be a bigger effort than simply creating those lists you need.
This can be done with a recursive function that adds with each step what value to add to the list until a defined size:
def gen_list(pre, size):
if size == 1:
return [pre]
res = gen_list(pre + [pre[-1]], size - 1)
res.extend(gen_list(pre + [pre[-1]+1], size-1))
return res
for l in gen_list([1], 4):
print(l)
Which prints:
[1, 1, 1, 1]
[1, 1, 1, 2]
[1, 1, 2, 2]
[1, 1, 2, 3]
[1, 2, 2, 2]
[1, 2, 2, 3]
[1, 2, 3, 3]
[1, 2, 3, 4]

How to isolate values from a list in Python?

I have a few lists I'm trying to investigate.I'm stuck at some point:
D = [1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 3, 2, 1, 1]
Let's say this is the list. I need to isolate a new list from the list D.We can say I want to filter those "1"'s; but I couldn't manage it.
If I use "index" method like:
D = [1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 3, 2, 1, 1]
E = []
for i in D:
if not i == 1:
E.append(D.index(i))
print(E)
The output is: [3, 4, 10, 3].What I need is [3, 4, 10, 11].Since values are at D[3] and D[11] are the same, python does not allow me to get the second one.How can I solve this?
Your help is highly appreciated.
Thanks.
You can write this program in many ways. I will try to adapt your example with minimal changes first:
D = [1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 3, 2, 1, 1]
E = []
for i in range(len(D)):
if D[i] != 1:
E.append(i)
print(E)
However, there is also a shorter/simpler one-line solution:
D = [1, 1, 1, 2, 5, 1, 1, 1, 1, 1, 3, 2, 1, 1]
E = [i for i in range(len(D)) if D[i]!=1]
print(E)
You can use a conditional list comprehension to enumerate the values in D and get the index locations of those values that match your condition.
>>> [idx for idx, val in enumerate(D) if val != 1]
[3, 4, 10, 11]
Note that you can also use filter to create a generator of the values at those index locations.
>>> list(filter(lambda val: val != 1, D))
[2, 5, 3, 2]
Using the index function indeed always returns the first occurence. From the documentation:
list.index(x[, start[, end]])
Return zero-based index in the list of the first item whose value is equal to x. Raises a ValueError if there is no such item.
...
We can use list comprehensions and combine this with enumerate to get what you want:
[index for index, value in enumerate(D) if value != 1]
# [3, 4, 10, 11]

Repeat list if index range is out of bounds

I have a Python list
a = [1, 2, 3, 4]
and I'd like to get a range of indices such that if I select the indices 0 through N, I'm getting (for N=10) the repeated
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
I could of course repeat the list via (int(float(N) / len(a) - 0.5) + 1) * a first and select the range [0:10] out of that, but that feels rather clumsy.
Any hints?
You can simply use the modulo operator when accessing the list, i.e.
a[i % len(a)]
This will give you the same result, but doesn't require to actually store the redundant elements.
You can use itertools.cycle and itertools.islice:
from itertools import cycle, islice
my_list = list(islice(cycle(my_list), 10))
Note that if you just want to iterate over this once, you should avoid calling list and just iterate over the iterable, since this avoids allocating repeated elements.
One easy way is to use modulo with list comprehensions à la
a = [1, 2, 3 ,4]
[k % len(a) for k in range(10)]
>>> a = [1, 2, 3, 4]
>>> (a*3)[:-2]
>>> [1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
Thought I would offer a solution using the * operator for lists.
import math
def repeat_iterable(a, N):
factor = N / len(a) + 1
repeated_list = a * factor
return repeated_list[:N]
Sample Output:
>>> print repeat_iterable([1, 2, 3, 4], 10)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
>>> print repeat_iterable([1, 2, 3, 4], 3)
[1, 2, 3]
>>> print repeat_iterable([1, 2, 3, 4], 0)
[]
>>> print repeat_iterable([1, 2, 3, 4], 14)
[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2]
How about faking it? Python is good at faking.
class InfiniteList(object):
def __init__(self, data):
self.data = data
def __getitem__(self, i):
return self.data[i % len(self.data)]
x = InfiniteList([10, 20, 30])
x[0] # 10
x[34] # 20
Of course, you could add __iter__, support for slices etc. You could also add a limit (N), but this is the general idea.

Consecutive numbers list where each number repeats

How can I create a list of consecutive numbers where each number repeats N times, for example:
list = [0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
Another idea, without any need for other packages or sums:
[x//N for x in range((M+1)*N)]
Where N is your number of repeats and M is the maximum value to repeat. E.g.
N = 3
M = 5
[x//N for x in range((M+1)*N)]
yields
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5]
My first instinct is to get some functional help from the funcy package. If N is the number of times to repeat each value, and M is the maximum value to repeat, then you can do
import funcy as fp
fp.flatten(fp.repeat(i, N) for i in range(M + 1))
This will return a generator, so to get the array you can just call list() around it
sum([[i]*n for i in range(0,x)], [])
The following piece of code is the simplest version I can think of.
It’s a bit dirty and long, but it gets the job done.
In my opinion, it’s easier to comprehend.
def mklist(s, n):
l = [] # An empty list that will contain the list of elements
# and their duplicates.
for i in range(s): # We iterate from 0 to s
for j in range(n): # and appending each element (i) to l n times.
l.append(i)
return l # Finally we return the list.
If you run the code …:
print mklist(10, 2)
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]
print mklist(5, 3)
[0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
Another version a little neater, with list comprehension.
But uhmmm… We have to sort it though.
def mklist2(s, n):
return sorted([l for l in range(s) * n])
Running that version will give the following results.
print mklist2(5, 3)
Raw : [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4]
Sorted: [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]

Categories