How to isolate values from a list in Python? - 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]

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]

Python: choosing indices from array that correspond to elements of specific value

I have an array that looks like this:
x = [1, 1, 2, 3, 3, 2, 2, 1, 2, 3, 2, 3, 2, 1, 2, 1, 1, 2, 1]
I want to write a function that will randomly return some specified number of indices that correspond to a specified number. In other words, if I pass the function the array x, the desired number of indices such as 3, and the target value 1, I would want it to return an array such as:
[0, 7, 13]
Since 0, 7, and 13 are the indices that correspond to 1 in x.
Does anyone know how I might do this efficiently?
You want to use random.sample for this:
import random
def f(arr, target, num):
return random.sample([i for i, x in enumerate(arr) if x == target], k=num)
x = [1, 1, 2, 3, 3, 2, 2, 1, 2, 3, 2, 3, 2, 1, 2, 1, 1, 2, 1]
print(f(x, 1, 3))
Output:
[0, 1, 15]
You can use the sample function from the random module and pass it the list of indices that match the specified value:
x = [1, 1, 2, 3, 3, 2, 2, 1, 2, 3, 2, 3, 2, 1, 2, 1, 1, 2, 1]
from random import sample
def randomIndices(a,count,v):
return sample([i for i,n in enumerate(a) if n==v],count)
print(randomIndices(x,3,1)) # [1,18,15]
Your question asks how to do this efficiently, which depends on how you plan on using this code. As myself and others have pointed out, one way is to use enumerate to filter the list for the indices that correspond to the target value. The downside here is that each time you pick a new target value or request a new sample, you have to once again enumerate the list which is an O(n) operation.
If you plan on taking multiple samples, you may be better off building a dictionary mapping the target value to the indices upfront. Then you can subsequently use this dictionary to draw random samples more efficiently than enumerating. (The magnitude of the savings would grow as x becomes very large).
First build the dictionary using collections.defaultdict:
from collections import defaultdict
d = defaultdict(list)
for i, val in enumerate(x):
d[val].append(i)
print(dict(d))
#{1: [0, 1, 7, 13, 15, 16, 18], 2: [2, 5, 6, 8, 10, 12, 14, 17], 3: [3, 4, 9, 11]}
Now you can use d to draw your samples:
from random import sample
def get_random_sample(d, target_value, size):
return sample(d[target_value], size)
print(get_random_sample(d, target_value=1, size=3))
#[16, 7, 18]
You can do the next:
Get the indices of the items with value equal to 1
Use random.sample to select randomly only a few indices (without repetitions) extracted from the previous step.
Here is one way to do it (n indicates the number of indices to pick):
from random import sample
x = [1, 1, 2, 3, 3, 2, 2, 1, 2, 3, 2, 3, 2, 1, 2, 1, 1, 2, 1]
n = 3
target = 1
indices = frozenset(filter(lambda k: x[k] == target, range(len(x))))
out = sample(indices, min(len(indices), n))
print(out)
Note that the number of returned indices could be lower than n (if the number of 1s in the list is less than n)

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

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]

Getting sublist with repeated elements in Python [duplicate]

I faced some problem with solving the next problem:
We have a list of elements (integers), and we should return a list consisting of only the non-unique elements in this list. Without changing order of the list
I think the best way is to delete or remove all unique element.
Take note that I just start to learn python and would like only the simplest solutions.
Here is my code:
def checkio(data):
for i in data:
if data.count(i) == 1: #if element seen in the list just ones, we delet this el
ind = data.index(i)
del data[ind]
return data
Your function can be made to work by iterating over the list in reverse:
def checkio(data):
for index in range(len(data) - 1, -1, -1):
if data.count(data[index]) == 1:
del data[index]
return data
print(checkio([3, 3, 5, 8, 1, 4, 5, 2, 4, 4, 3, 0]))
[3, 3, 5, 4, 5, 4, 4, 3]
print(checkio([1, 2, 3, 4]))
[]
This works, because it only deletes numbers in the section of the list that has already been iterated over.
Just I used list Comprehensions.
def checkio(data):
a=[i for i in data if data.count(i)>1]
return a
print checkio([1,1,2,2,1,1,1,3,4,5,6,7,8])
You can implement a OrderedCounter, eg:
from collections import OrderedDict, Counter
class OrderedCounter(Counter, OrderedDict):
pass
data = [1, 3, 1, 2, 3, 5, 8, 1, 5, 2]
duplicates = [k for k, v in OrderedCounter(data).items() if v > 1]
# [1, 3, 2, 5]
So you count the occurrence of each value, then filter on if it has a frequency of more than one. Inheriting from OrderedDict means the order of the original elements is preserved.
Going by comments, you want all duplicated elements reserved, so you can pre-build a set of the duplicate entries, then re-iterate your original list, eg:
from collections import Counter
data = [1, 3, 1, 2, 3, 5, 8, 1, 5, 2]
duplicates = {k for k, v in Counter(data).items() if v > 1}
result = [el for el in data if el in duplicates]
# [1, 3, 1, 2, 3, 5, 1, 5, 2]
Try this:
>>> a=[1,2,3,3,4,5,6,6,7,8,9,2,0,0]
>>> a=[i for i in a if a.count(i)>1]
>>> a
[2, 3, 3, 6, 6, 2, 0, 0]
>>> a=[1, 2, 3, 1, 3]
>>> a=[i for i in a if a.count(i)>1]
>>> a
[1, 3, 1, 3]
>>> a=[1, 2, 3, 4, 5]
>>> a=[i for i in a if a.count(i)>1]
a
[]
def checkio(data):
lis = []
for i in data:
if data.count(i)>1:
lis.append(i)
print(lis)
checkio([1,2,3,3,2,1])
Yeah it's a bit late to contribute to this thread but just wanted to put it there on the net for anyone else use.
Following what you have started, iterating on the list of integers, but not counting or deleting elements, try just testing if the element has already been seen, append it to a list of duplicated elements:
def checkio(data):
elements = []
duplicates = []
for i in data:
if i not in elements:
elements.append(i)
else:
if i not in duplicates:
duplicates.append(i)
return duplicates
d = [1, 3, 1, 2, 3, 5, 8, 1, 5, 2]
print (checkio(d))
#[1, 3, 5, 2]
numbers = [1, 1, 1, 1, 3, 4, 9, 0, 1, 1, 1]
x=set(numbers)
print(x)
You can use the set key word too to get the desired solution.
I used an integer and bool to check every time the list was modified within a while loop.
rechecks = 1
runscan = True
while runscan == True:
for i in data:
if data.count(i) <2:
data.remove(i)
rechecks+=1
#need to double check now
if rechecks >0:
runscan = True
rechecks-=1
else:
runscan = False
return data
Would it not be easier to generate a new list?
def unique_list(lst):
new_list = []
for value in lst:
if value not in new_list:
new_list.append(value)
return new_list
lst = [1,2,3,1,4,5,1,6,2,3,7,8,9]
print(unique_list(lst))
Prints [1,2,3,4,5,6,7,8,9]

Python List ordering

I have a list a = [2, 2, 1, 0, 3, 2, 1, 1, 0, 0].
I want the output to be order = [5, 1, 2, 6, 3, 7, 8].
The output should be a list of index+1 of the elements arranged in non-increasing order of a and wherever there is same value of a it should be arranged in increasing order of index. Here index of max element is 4 so 5 comes first and then there are indexes 0, 1, 5. So 1, 2, 6 comes.
Is there any short pythonic way to achieve this without using loops?
I have tried this with reverse = True
order = [i+1 for (v,i) in sorted(((v, i) for (i, v) in enumerate(a)),reverse=True)].
But this does not keep the indexes as desired wherever there is same value.
I'm guessing that you don't want zeros indices in your result.
The key parameter of sorted() is what you're looking for.
Try this :
a = [2, 2, 1, 0, 3, 2, 1, 1, 0, 0]
order = [ i + 1 for (i, n) in sorted(enumerate(a), key=lambda t: t[1], reverse=True) if n > 0 ]
See the sorted() documentation for more details.
But this does not keep the indexes as desired wherever there is same value.
It does, but you are sorting in reverse! So the indices for 1 - 1, 2 and 6 - are coming ordered 6, 2, 1. Flip the index to sort correctly:
[-i+1 for (v,i) in sorted(((v, -i) for (i, v) in enumerate(a)),reverse=True)]
# => [5, 1, 2, 6, 3, 7, 8, 4, 9, 10]

Categories