I am trying to randomly replace 20% of a list in python:
ls = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ls = [1, 2, NULL, 4, 5, 6, NULL, 8, 9, 10]
ls = [1, 2, 82, 4, 5, 6, 28, 8, 9, 10]
so far
while n <= len(ls)/5
ls[randint(0, 9)]=randint(1, 100)
n += 1
but it has a fairly large chance of removing and replacing the same entry multiple times in one run.
Assuming ls could be anything, I would recommend generating a list of indices, corresponding to ls. Then, you may use random.sample to pick up 20% of those indices, and then alter those only.
From the docs:
Return a k length list of unique elements chosen from the population
sequence. Used for random sampling without replacement.
In [816]: for _i in random.sample(range(len(ls)), len(ls) // 5):
...: ls[_i] = random.randint(1, 100)
...:
In [817]: ls
Out[817]: [1, 92, 3, 4, 5, 6, 7, 8, 75, 10]
Unless your lists are very large, you can select a sample from the indexes. For example:
for idx in random.sample(range(len(ls)), len(ls)/5):
ls[idx]=random.randint(1, 100)
You can shuffle a range of indexes and then take first n indexes that has to be changed.
from random import shuffle
x = [[i] for i in range(10)]
shuffle(x)
#change x[0], x[1], .. x[n-1]
If you want to eliminate the chance of the same index getting replaced the second time, you can store the result of randint(0, 9) in a variable. In the next iterations, use an if condition to check if randint() returned the same index as the previous iteration. If yes, then continue and do not increment n.
Alternatively, you can use random.sample() to pick up a given number of samples - 20% of the list size in your case.
Best option would be to pick 20% worth of indexes and then replace them in the list. Something like:
from random import randint
twenty_percent = round(len(ls) / 5)
for i in range(twenty_percent):
ls[randint(0, len(ls) - 1)] = randint(1, 100)
This answer takes INDEX into account, so it won't replace the same value twice.
ls = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
n = len(ls)
x = round(n/5)
for i in range(x):
index = randint(0, n)
del ls[index]
ls.insert(index, randint(0, 100))
print(ls)
Works for me. See if it does the job.
Related
I need to pick out "x" number of non-repeating, random numbers out of a list. For example:
all_data = [1, 2, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 15]
How do I pick out a list like [2, 11, 15] and not [3, 8, 8]?
That's exactly what random.sample() does.
>>> random.sample(range(1, 16), 3)
[11, 10, 2]
Edit: I'm almost certain this is not what you asked, but I was pushed to include this comment: If the population you want to take samples from contains duplicates, you have to remove them first:
population = [1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]
population = list(set(population))
samples = random.sample(population, 3)
Something like this:
all_data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
from random import shuffle
shuffle(all_data)
res = all_data[:3]# or any other number of items
OR:
from random import sample
number_of_items = 4
sample(all_data, number_of_items)
If all_data could contains duplicate entries than modify your code to remove duplicates first and then use shuffle or sample:
all_data = list(set(all_data))
shuffle(all_data)
res = all_data[:3]# or any other number of items
Others have suggested that you use random.sample. While this is a valid suggestion, there is one subtlety that everyone has ignored:
If the population contains repeats,
then each occurrence is a possible
selection in the sample.
Thus, you need to turn your list into a set, to avoid repeated values:
import random
L = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
random.sample(set(L), x) # where x is the number of samples that you want
Another way, of course with all the solutions you have to be sure that there are at least 3 unique values in the original list. all_data = [1,2,2,3,4,5,6,7,8,8,9,10,11,11,12,13,14,15,15]
choices = []
while len(choices) < 3:
selection = random.choice(all_data)
if selection not in choices:
choices.append(selection)
print choices
You can also generate a list of random choices, using itertools.combinations and random.shuffle.
all_data = [1,2,2,3,4,5,6,7,8,8,9,10,11,11,12,13,14,15,15]
# Remove duplicates
unique_data = set(all_data)
# Generate a list of combinations of three elements
list_of_three = list(itertools.combinations(unique_data, 3))
# Shuffle the list of combinations of three elements
random.shuffle(list_of_three)
Output:
[(2, 5, 15), (11, 13, 15), (3, 10, 15), (1, 6, 9), (1, 7, 8), ...]
import random
fruits_in_store = ['apple','mango','orange','pineapple','fig','grapes','guava','litchi','almond']
print('items available in store :')
print(fruits_in_store)
my_cart = []
for i in range(4):
#selecting a random index
temp = int(random.random()*len(fruits_in_store))
# adding element at random index to new list
my_cart.append(fruits_in_store[temp])
# removing the add element from original list
fruits_in_store.pop(temp)
print('items successfully added to cart:')
print(my_cart)
Output:
items available in store :
['apple', 'mango', 'orange', 'pineapple', 'fig', 'grapes', 'guava', 'litchi', 'almond']
items successfully added to cart:
['orange', 'pineapple', 'mango', 'almond']
If the data being repeated implies that we are more likely to draw that particular data, we can't turn it into a set right away (since we would loose that information by doing so). For this, we need to pick samples one by one and verify the size of the set that we generate has reached x (the number of samples that we want). Something like:
data=[0, 1, 2, 3, 4, 4, 4, 4, 5, 5, 6, 6]
x=3
res=set()
while(len(res)<x):
res.add(np.random.choice(data))
print(res)
some outputs :
{3, 4, 5}
{3, 5, 6}
{0, 4, 5}
{2, 4, 5}
As we can see 4 or 5 appear more frequently (I know 4 examples is not good enough statistics).
I am trying to solve a assignment where are 13 lights and starting from 1, light is turned off at every 5th light, when the count reaches 13, start from 1st item again. The function should return the order of lights turned off. In this case, for a list of 13 items, the return list would be [5, 10, 2, 8, 1, 9, 4, 13, 12, 3, 7, 11, 6]. Also, turned off lights would not count again.
So the way I was going to approach this problem was to have a list named turnedon, which is [1,2,3,4,5,6,7,8,9,10,11,12,13] and an empty list called orderoff and append to this list whenever a light gets turned off in the turnedon list. So while the turnedon is not empty, iterate through the turnedon list and append the light getting turned off and remove that turnedoff light from the turnedon list, if that makes sense. I cannot figure out what should go into the while loop though. Any idea would be really appreciated.
def orderoff():
n=13
turnedon=[]
for n in range(1,n+1):
turnedon.append(n)
orderoff=[]
while turneon !=[]:
This problem is equivalent to the well-known Josephus problem, in which n prisoners stand in a circle, and they are killed in a sequence where each time, the next person to be killed is k steps around the circle from the previous person; the steps are only counted over the remaining prisoners. A sample solution in Python can be found on the Rosetta code website, which I've adapted slightly below:
def josephus(n, k):
p = list(range(1, n+1))
i = 0
seq = []
while p:
i = (i+k-1) % len(p)
seq.append(p.pop(i))
return seq
Example:
>>> josephus(13, 5)
[5, 10, 2, 8, 1, 9, 4, 13, 12, 3, 7, 11, 6]
This works, but the results are different from yours:
>>> pos = 0
>>> result = []
>>> while len(result) < 13 :
... pos += 5
... pos %= 13
... if pos not in result :
... result.append(pos)
...
>>> result = [i+1 for i in result] # make it 1-based, not 0-based
>>> result
[6, 11, 3, 8, 13, 5, 10, 2, 7, 12, 4, 9, 1]
>>>
I think a more optimal solution would be to use a loop, add the displacement each time, and use modules to keep the number in range
def orderoff(lights_num,step):
turnd_off=[]
num =0
for i in range(max):
num =((num+step-1)%lights_num)+1
turnd_off.append(num)
return turnd_off
print(orderoff(13))
I am using the itertools library module in python.
I am interested the different ways to choose 15 of the first 26000 positive integers. The function itertools.combinations(range(1,26000), 15) enumerates all of these possible subsets, in a lexicographical ordering.
The binomial coefficient 26000 choose 15 is a very large number, on the order of 10^54. However, python has no problem running the code y = itertools.combinations(range(1,26000), 15) as shown in the sixth line below.
If I try to do y[3] to find just the 3rd entry, I get a TypeError. This means I need to convert it into a list first. The problem is that trying to convert it into a list gives a MemoryError. All of this is shown in the screenshot above.
Converting it into a list does work for smaller combinations, like 6 choose 3, shown below.
My question is:
Is there a way to access specific elements in itertools.combinations() without converting it into a list?
I want to be able to access, say, the first 10000 of these ~10^54 enumerated 15-element subsets.
Any help is appreciated. Thank you!
You can use a generator expression:
comb = itertools.combinations(range(1,26000), 15)
comb1000 = (next(comb) for i in range(1000))
To jump directly to the nth combination, here is an itertools recipe:
def nth_combination(iterable, r, index):
"""Equivalent to list(combinations(iterable, r))[index]"""
pool = tuple(iterable)
n = len(pool)
if r < 0 or r > n:
raise ValueError
c = 1
k = min(r, n-r)
for i in range(1, k+1):
c = c * (n - k + i) // i
if index < 0:
index += c
if index < 0 or index >= c:
raise IndexError
result = []
while r:
c, n, r = c*r//n, n-1, r-1
while index >= c:
index -= c
c, n = c*(n-r)//n, n-1
result.append(pool[-1-n])
return tuple(result)
It's also available in more_itertools.nth_combination
>>> import more_itertools # pip install more-itertools
>>> more_itertools.nth_combination(range(1,26000), 15, 123456)
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 18, 19541)
To instantly "fast-forward" a combinations instance to this position and continue iterating, you can set the state to the previously yielded state (note: 0-based state vector) and continue from there:
>>> comb = itertools.combinations(range(1,26000), 15)
>>> comb.__setstate__((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 17, 19540))
>>> next(comb)
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 18, 19542)
If you want to access the first few elements, it's pretty straightforward with islice:
import itertools
print(list(itertools.islice(itertools.combinations(range(1,26000), 15), 1000)))
Note that islice internally iterates the combinations up to the specified point, so it can't magically give you the middle elements without iterating all the way there. You'd have to go down the route of computing the elements you want combinatorially in that case.
I want to print the top 10 distinct elements from a list:
top=10
test=[1,1,1,2,3,4,5,6,7,8,9,10,11,12,13]
for i in range(0,top):
if test[i]==1:
top=top+1
else:
print(test[i])
It is printing:
2,3,4,5,6,7,8
I am expecting:
2,3,4,5,6,7,8,9,10,11
What I am missing?
Using numpy
import numpy as np
top=10
test=[1,1,1,2,3,4,5,6,7,8,9,10,11,12,13]
test=np.unique(np.array(test))
test[test!=1][:top]
Output
array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
Since you code only executes the loop for 10 times and the first 3 are used to ignore 1, so only the following 3 is printed, which is exactly happened here.
If you want to print the top 10 distinct value, I recommand you to do this:
# The code of unique is taken from [remove duplicates in list](https://stackoverflow.com/questions/7961363/removing-duplicates-in-lists)
def unique(l):
return list(set(l))
def print_top_unique(List, top):
ulist = unique(List)
for i in range(0, top):
print(ulist[i])
print_top_unique([1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 10)
My Solution
test = [1,1,1,2,3,4,5,6,7,8,9,10,11,12,13]
uniqueList = [num for num in set(test)] #creates a list of unique characters [1,2,3,4,5,6,7,8,9,10,11,12,13]
for num in range(0,11):
if uniqueList[num] != 1: #skips one, since you wanted to start with two
print(uniqueList[num])
I am trying to do the following..
I have a list of n elements. I want to split this list into 32 separate lists which contain more and more elements as we go towards the end of the original list. For example from:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
I want to get something like this:
b = [[1],[2,3],[4,5,6,7],[8,9,10,11,12]]
I've done the following for a list containing 1024 elements:
for i in range (0, 32):
c = a[i**2:(i+1)**2]
b.append(c)
But I am stupidly struggling to find a reliable way to do it for other numbers like 256, 512, 2048 or for another number of lists instead of 32.
Use an iterator, a for loop with enumerate and itertools.islice:
import itertools
def logsplit(lst):
iterator = iter(lst)
for n, e in enumerate(iterator):
yield itertools.chain([e], itertools.islice(iterator, n))
Works with any number of elements. Example:
for r in logsplit(range(50)):
print(list(r))
Output:
[0]
[1, 2]
[3, 4, 5]
[6, 7, 8, 9]
... some more ...
[36, 37, 38, 39, 40, 41, 42, 43, 44]
[45, 46, 47, 48, 49]
In fact, this is very similar to this problem, except it's using enumerate to get variable chunk sizes.
This is incredibly messy, but gets the job done. Note that you're going to get some empty bins at the beginning if you're logarithmically slicing the list. Your examples give arithmetic index sequences.
from math import log, exp
def split_list(_list, divs):
n = float(len(_list))
log_n = log(n)
indices = [0] + [int(exp(log_n*i/divs)) for i in range(divs)]
unfiltered = [_list[indices[i]:indices[i+1]] for i in range(divs)] + [_list[indices[i+1]:]]
filtered = [sublist for sublist in unfiltered if sublist]
return [[] for _ in range(divs- len(filtered))] + filtered
print split_list(range(1024), 32)
Edit: After looking at the comments, here's an example that may fit what you want:
def split_list(_list):
copy, output = _list[:], []
length = 1
while copy:
output.append([])
for _ in range(length):
if len(copy) > 0:
output[-1].append(copy.pop(0))
length *= 2
return output
print split_list(range(15))
# [[0], [1, 2], [3, 4, 5, 6], [7, 8, 9, 10, 11, 12, 13, 14]]
Note that this code is not efficient, but it can be used as a template for writing a better algorithm.
Something like this should solve the problem.
for i in range (0, int(np.sqrt(2*len(a)))):
c = a[i**2:min( (i+1)**2, len(a) )]
b.append(c)
Not very pythonic but does what you want.
def splitList(a, n, inc):
"""
a list to split
n number of sublist
inc ideal difference between the number of elements in two successive sublists
"""
zr = len(a) # remaining number of elements to split into sublists
st = 0 # starting index in the full list of the next sublist
nr = n # remaining number of sublist to construct
nc = 1 # number of elements in the next sublist
#
b=[]
while (zr/nr >= nc and nr>1):
b.append( a[st:st+nc] )
st, zr, nr, nc = st+nc, zr-nc, nr-1, nc+inc
#
nc = int(zr/nr)
for i in range(nr-1):
b.append( a[st:st+nc] )
st = st+nc
#
b.append( a[st:max(st+nc,len(a))] )
return b
# Example of call
# b = splitList(a, 32, 2)
# to split a into 32 sublist, where each list ideally has 2 more element
# than the previous
There's always this.
>>> def log_list(l):
if len(l) == 0:
return [] #If the list is empty, return an empty list
new_l = [] #Initialise new list
new_l.append([l[0]]) #Add first iteration to new list inside of an array
for i in l[1:]: #For each other iteration,
if len(new_l) == len(new_l[-1]):
new_l.append([i]) #Create new array if previous is full
else:
new_l[-1].append(i) #If previous not full, add to it
return new_l
>>> log_list([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]