Picking unique random numbers from a range [duplicate] - python

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).

Related

Returning a list of the ordered elements with a conition in while loop structure

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))

Printing top n distinct values of a list

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])

Python: replace 20% of a list

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.

How to split lists into smaller lists at certain points in python? [duplicate]

This question already has answers here:
How do I split a list into equally-sized chunks?
(66 answers)
Closed 8 years ago.
I have a list of different things and I was wondering how to split it every time it hits a new name?
So what I would like to have is have it take a list that looks like this:
list = [corn, 14, 2, 500, broccoli, 2, 10, 1400, potato, 2, 14, 7]
and it will create 3 lists:
list1 = [corn, 14, 2, 500]
list2 = [broccoli, 2, 10, 1400]
list3 = [potato, 2, 14, 7]
I am guessing it would be something along the lines of a loop that repeats a new list until it hits a non integer, but I really dont know how it would look set up.
Try this, assuming that new names appear every four elements as in the sample input:
lst = ['corn', 14, 2, 500, 'broccoli', 2, 10, 1400, 'potato', 2, 14, 7]
[lst[i:i+4] for i in xrange(0, len(lst), 4)]
=> [['corn', 14, 2, 500], ['broccoli', 2, 10, 1400], ['potato', 2, 14, 7]]
The above will return a list of sublists, split every four elements. If you're certain that there will be exactly twelve elements in the input list, it's possible to directly assign the resulting sublists:
lst1, lst2, lst3 = [lst[i:i+4] for i in xrange(0, len(lst), 4)]
Now each variable will contain the expected result:
lst1
=> ['corn', 14, 2, 500]
lst2
=> ['broccoli', 2, 10, 1400]
lst3
=> ['potato', 2, 14, 7]
For checking if a String is a number (and don't forget to include quotation marks if you're going to use that code exactly), look at str.isdigit().
I.e.
>>> 'corn'.isdigit()
False
>>> '123'.isdigit()
True
This may not be the prettiest solution but it's able to respond when the delimiter size changes (say you want to track another number between corn and broccoli) and also allows it to grow beyond a set of three lists if you want.
lst = ["corn", 14, 2, 500, "broccoli", 2, 10, 1400, "potato", 2, 14, 7]
string_indices = [index for (index, value) in enumerate(lst)
if isinstance(value, str)]
# We want to include the last group as well
string_indices.append(len(lst))
sublists = [lst[string_indices[x]:string_indices[x+1]]
for x in xrange(len(string_indices) - 1)]
lst1, lst2, lst3 = sublists
At the end, sublists is equal to:
[['corn', 14, 2, 500], ['broccoli', 2, 10, 1400], ['potato', 2, 14, 7]]
...and it unpacks into the three lists as shown above.
This is hideous but will get the job done for ya.
l = ["corn", 14, 2, 500, "broccoli", 2, 10, 1400, "potato", 2, 14, 7, 5, 6, 7, "carrot"]
out = []
for i in xrange(0, len(l)):
if isinstance(l[i], str):
tmp = []
tmp.append(l[i])
i += 1
while (i < len(l)) and isinstance(l[i], int) :
tmp.append(l[i])
i += 1
out.append(tmp)
In [41]: out
Out[41]:
[['corn', 14, 2, 500],
['broccoli', 2, 10, 1400],
['potato', 2, 14, 7, 5, 6, 7],
['carrot']]
There are two problems in the single line of code that you posted
it's likely that you want to use strings rather than generic objects
in your list
list is a python function that creates a list from a sequence or
an iterable and deserves to be let on its own, so we name your list
a_list
What follows is based on a single assumption, that you want to split on each string and only on strings
a_list = ['corn', 14, 2, 500, 'broccoli', 2, 10, 1400, 'potato', 2, 14, 7]
# initialize an empty list (I can do it in other ways, but I want
# to show you an use of the `list` builtin function) and a counter `n`
list_of_sublists = list() # the function 'list' is called with no arguments
n = 0
# iterate for the index and the corresponding element of the list
for i, elt in enumerate(a_list):
# when we reach the second string in the list we append the sublist
# from the previous beginning `n=0`, do you remember? up to the current
# index, that in python is _excluded_ from the sublist, and finally we
# update the index for the start of the next sublist
# NOTA BENE the SECOND string triggers the saving of the FIRST sublist
if i and type(elt) == str:
list_of_sublists.append(a_list[n:i])
n = i
# and of course the code above is triggered for the third, the ...,
# the last string in the list
# but when we reach the end of the loop, having found that there are no
# further strings past the last one ;-) we have still the last sublist,
# the one that starts with the last string, that waits for being appended
# so here we do this last append
list_of_sublists.append(a_list[n:])
print list_of_sublists
Someone will object that the test type(elt) == str will fail for objects that are subclassed from str, or that quacks like a str, but I assume that you have 'nuff stuff to think about already...

Merge python lists in a specific order/sequence

I'm trying to make two lists of the sort:
list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
into
list_both= ["onetothree",1,2,3,"fourtosix",4,5,6...]
This is just a way to describe my problem. I need to do this with all the elements in list_numbers & list_letters. The number or elements in list_numbers will always be dividable by the amount of elements in list_letters so theres no need to worry about "crooked data".
After searching for a good three hours, trying with many different kinds of "for" and "while" loops and only getting python 2.x questions, bad results and syntax errors, I thought I'd maybe deserve to post this question.
Hacky, but it'll get the job done
>>> list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
>>> list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
>>> list(itertools.chain.from_iterable(zip(list_letters, *zip(*[list_numbers[i:i+3] for i in range(0, len(list_numbers), 3)]))))
['onetothree', 1, 2, 3, 'fourtosix', 4, 5, 6, 'seventonine', 7, 8, 9, 'tentotwelve', 10, 11, 12]
Or, the cleaner version:
>>> answer = []
>>> i = 0
>>> for letter in list_letters:
... answer.append(letter)
... for j in range(3):
... answer.append(list_numbers[i+j])
... i += j+1
...
>>> answer
['onetothree', 1, 2, 3, 'fourtosix', 4, 5, 6, 'seventonine', 7, 8, 9, 'tentotwelve', 10, 11, 12]
Of course, if you don't have sufficiently many entries in list_numbers, you this will burn you
try this:
list_numbers = [1,2,3,4,5,6,7,8,9,10,11,12]
list_letters= ["onetothree", "fourtosix", "seventonine", "tentotwelve"]
list_both=[]
c=1
for n in range(len(list_letters)):
list_both.append(list_letters[n])
list_both[c+n:c+n]=list_numbers[c-1:c+2]
c+=3
print(list_both)

Categories

Resources