How to randomly select a specific sequence from a list? - python

I have a list of hours starting from (0 is midnight).
hour = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
I want to generate a sequence of 3 consecutive hours randomly. Example:
[3,6]
or
[15, 18]
or
[23,2]
and so on. random.sample does not achieve what I want!
import random
hourSequence = sorted(random.sample(range(1,24), 2))
Any suggestions?

Doesn't exactly sure what you want, but probably
import random
s = random.randint(0, 23)
r = [s, (s+3)%24]
r
Out[14]: [16, 19]

Note: None of the other answers take in to consideration the possible sequence [23,0,1]
Please notice the following using itertools from python lib:
from itertools import islice, cycle
from random import choice
hours = list(range(24)) # List w/ 24h
hours_cycle = cycle(hours) # Transform the list in to a cycle
select_init = islice(hours_cycle, choice(hours), None) # Select a iterator on a random position
# Get the next 3 values for the iterator
select_range = []
for i in range(3):
select_range.append(next(select_init))
print(select_range)
This will print sequences of three values on your hours list in a circular way, which will also include on your results for example the [23,0,1].

You can try this:
import random
hour = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
index = random.randint(0,len(hour)-2)
l = [hour[index],hour[index+3]]
print(l)

You can get a random number from the array you already created hour and take the element that is 3 places afterward:
import random
def random_sequence_endpoints(l, span):
i = random.choice(range(len(l)))
return [hour[i], hour[(i+span) % len(l)]]
hour = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
result = random_sequence_endpoints(hour, 3)
This will work not only for the above hours list example but for any other list contain any other elements.

Related

How to calculate median from 2 different lists in Python

I have two lists note = [6,8,10,13,14,17] Effective = [3,5,6,7,5,1] ,the first one represents grades, the second one the students in the class that got that grade. so 3 kids got a 6 and 1 got a 17. I want to calculate the mean and the median. for the mean I got:
note = [6,8,10,13,14,17]
Effective = [3,5,6,7,5,1]
products = [] for num1, num2 in zip(note, Effective):
products.append(num1 * num2)
print(sum(products)/(sum(Effective)))
My first question is, how do I turn both lists into a 3rd list:
(6,6,6,8,8,8,8,8,10,10,10,10,10,10,13,13,13,13,13,13,13,14,14,14,14,14,17)
in order to get the median.
Thanks,
Donka
Here's one approach iterating over Effective on an inner level to replicate each number as many times as specified in Effective, and taking the median using statistics.median:
from statistics import median
out = []
for i in range(len(note)):
for _ in range(Effective[i]):
out.append(note[i])
print(median(out))
# 10
To get your list you could do something like
total = []
for grade, freq in zip(note, Effective):
total += freq*[grade]
You can use np.repeat to get a list with the new values.
note = [6,8,10,13,14,17]
Effective = [3,5,6,7,5,1]
import numpy as np
new_list = np.repeat(note,Effective)
np.median(new_list),np.mean(new_list)
To achieve output like the third list that you expect you have to do something like that:
from statistics import median
note = [6,8,10,13,14,17]
Effective = [3,5,6,7,5,1]
newList = []
for index,value in enumerate(Effective):
for j in range(value):
newList.append(note[index])
print(newList)
print("Median is {}".format(median(newList)))
Output:
[6, 6, 6, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 17]
Median is 10
For computing the median I suggest you use statistics.median:
from statistics import median
note = [6, 8, 10, 13, 14, 17]
effective = [3, 5, 6, 7, 5, 1]
total = [n for n, e in zip(note, effective) for _ in range(e)]
result = median(total)
print(result)
Output
10
If you look at total (in the code above), you have:
[6, 6, 6, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 17]
A functional alternative, using repeat:
from statistics import median
from itertools import repeat
note = [6, 8, 10, 13, 14, 17]
effective = [3, 5, 6, 7, 5, 1]
total = [v for vs in map(repeat, note, effective) for v in vs]
result = median(total)
print(result)
note = [6,8,10,13,14,17]
effective = [3,5,6,7,5,1]
newlist=[]
for i in range(0,len(note)):
for j in range(effective[i]):
newlist.append(note[i])
print(newlist)

Python list slicing for n-2 every n

If I have a list test
test = [i for i in range(20)]
print(test)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
and I want to get the last 3 numbers every 5 numbers such that I get a list that looks like:
[2, 3, 4, 7, 8, 9, 12, 13, 14, 17, 18, 19]
Is there a way to do this with list slicing? I can do it with a modulo function like
[i for i in test if i % 5 > 1]
But I'm wondering if there is a way to do this with list slicing? Thanks
Use the filter function:
list(filter(lambda x: x % 5 > 1, test)) # [2, 3, 4, 7, 8, 9, 12, 13, 14, 17, 18, 19]
If ordering does not matter, you can try the following:
test[2::5] + test[3::5] + test[4::5]
Or more generally speaking
start = 2 #Number of indices to skip
n = 5
new_test = []
while start < 5:
b.extend(test[start::n])
start += 1
Yes, but I very much doubt it will be faster than a simple list comprehension:
from itertools import chain, zip_longest as zipl
def offset_modulo(l, x, n):
sentinel = object()
slices = (l[i::n] for i in range(x, n))
iterable = chain.from_iterable(zipl(*slices, fillvalue=sentinel))
return list(filter(lambda x: x is not sentinel, iterable))
print(offset_modulo(range(20), 2, 5))
# [2, 3, 4, 7, 8, 9, 12, 13, 14, 17, 18, 19]
print(offset_modulo(range(24), 2, 5))
# [2, 3, 4, 7, 8, 9, 12, 13, 14, 17, 18, 19, 22, 23]
Basically, this approach gets the list slices that represents each the index i such that i % n >= x. It then uses zip and chain to flatten those into the output.
Edit:
A simpler way
def offset(l, x, n):
diff = n-x
slices = (l[i:i+diff] for i in range(x, len(l), n))
return list(chain.from_iterable(slices))
offset(range(20), 2, 5)
# [2, 3, 4, 7, 8, 9, 12, 13, 14, 17, 18, 19]
offset(range(24), 2, 5)
# [2, 3, 4, 7, 8, 9, 12, 13, 14, 17, 18, 19, 22, 23]
Where we get the slices of the adjacent elements we want, then chain those together.
I propose this solution:
from functools import reduce
reduce(lambda x, y: x + y, zip(test[2::5], test[3::5], test[4::5]))
Testing with timeit, it is faster than filter and comprehension list (at least on my pc).
Here the code to carry out an execution time comparison:
import numpy as np
import timeit
a = timeit.repeat('list(filter(lambda x: x % 5 > 1, test))',
setup='from functools import reduce; test = list(range(20))',
repeat=20,
number=100000)
b = timeit.repeat('[i for i in test if i % 5 > 1]',
repeat=20,
setup='test = list(range(20))',
number=100000)
c = timeit.repeat('reduce(lambda x, y: x + y, zip(test[2::5], test[3::5], test[4::5]))',
repeat=20,
setup='from functools import reduce;test = list(range(20))',
number=100000)
list(map(lambda x: print("{}:\t\t {} ({})".format(x[0], np.mean(x[1]), np.std(x[1]))),
[("filter list", a),
('comprehension', b),
('reduce + zip', c)]))
The previous code produce the following results:
filter list: 0.2983790061000036 (0.007463432805174629)
comprehension: 0.15115660065002884 (0.004455055805853705)
reduce + zip: 0.11976779574997636 (0.002553487341208172)
I hope this can help :)

how to generate many lists and assign values to them

I want to read a specific number of lines from a list and assign all those values to a new list. Then I want to read the next bunch from the last_value+1 line from before for the exact same number of lines and assign those to a new list. So far I have this:
Let's say u = [1,2,3....,9,10,11,12,13...,19,20] and I want to assign the first 10 values from u into my newly generated list1 = [] => list1 = [1,2,..9,10]
then I want the next 10 values from u to be assigned to list2 so list2 = [11,12,13..,20]. The code so far is:
nLines = 10
nrepeats = 2
j=0
i=0
while (j<nrepeats):
### Generating empty lists ###
mklist = "list" + str(j) + " = []"
### do the segmentation ###
for i, uline in enumerate(u):
if i >= i and i < i+nLines:
mklist.append(uline)
j=j+1
Now the problem is, that i cant append to mklist because it's a string:
AttributeError: 'str' object has no attribute 'append'
How can I assign those values within that loop?
You could use a more suitable collection, for example, a dictionary:
nLines = 10
nrepeats = 2
j=0
i=0
my_dict = {}
while (j<nrepeats):
### Generating empty lists ###
my_dict[str(j)] = []
### do the segmentation ###
for i, uline in enumerate(u):
if i >= i and i < i+nLines:
my_dict[str(j)].append(uline)
j=j+1
You can use the zip function to group elements from iterables into groups of the same size. There are actually two ways, that differ in how you way to handle cases where you can't divide the source data cleanly
u = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
The first way is with regular zip and discards the leftover fragment
>>>list(zip(*[iter(u)]*10))
[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (11, 12, 13, 14, 15, 16, 17, 18, 19, 20)]
The second way uses itertools.zip_longest and pads out the last group with some fillvalue (default None)
>>>import itertools
>>>list(itertools.zip_longest(*[iter(u)]*10, fillvalue=None))
[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (11, 12, 13, 14, 15, 16, 17, 18, 19, 20), (21, None, None, None, None, None, None, None, None, None)]

Python: How to range() multiple values from list or dictionary?

Im new to programming. Trying to range numbers - For example if i want to range more than one range, 1..10 20...30 50...100. Where i need to store them(list or dictionary) and how to use them one by one?
example = range(1,10)
exaple2 = range(20,30)
for b in example:
print b
or you can use yield from (python 3.5)
def ranger():
yield from range(1, 10)
yield from range(20, 30)
yield from range(50, 100)
for x in ranger():
print(x)
The range function returns a list. If you want a list of multiple ranges, you need to concatenate these lists. For example:
range(1, 5) + range(11, 15)
returns [1, 2, 3, 4, 11, 12, 13, 14]
Range module helps you to get numbers between the given input.
Syntax:
range(x) - returns list starting from 0 to x-1
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
range(x,y) - returns list starting from x to y-1
>>> range(10,20)
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>>
range(x,y,stepsize) - returns list starting from x to y-1 with stepsize
>>> range(10,20,2)
[10, 12, 14, 16, 18]
>>>
In Python3.x you can do:
output = [*range(1, 10), *range(20, 30)]
or using itertools.chain function:
from itertools import chain
data = [range(1, 10), range(20, 30)]
output = [*chain(*data)]
or using chain.from_iterable function
from itertools import chain
data = [range(1, 10), range(20, 30)]
output = [*chain.from_iterable(data)]
output:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]

Python intersection of multiple datetime lists

I'm trying to find the intersection list of 5 lists of datetime objects. I know the intersection of lists question has come up a lot on here, but my code is not performing as expected (like the ones from the other questions).
Here are the first 3 elements of the 5 lists with the exact length of the list at the end.
[datetime.datetime(2014, 8, 14, 19, 25, 6), datetime.datetime(2014, 8, 14, 19, 25, 7), datetime.datetime(2014, 8, 14, 19, 25, 9)] # length 38790
[datetime.datetime(2014, 8, 14, 19, 25, 6), datetime.datetime(2014, 8, 14, 19, 25, 7), datetime.datetime(2014, 8, 14, 19, 25, 9)] # length 38818
[datetime.datetime(2014, 8, 14, 19, 25, 6), datetime.datetime(2014, 8, 14, 19, 25, 7), datetime.datetime(2014, 8, 14, 19, 25, 9)] # length 38959
[datetime.datetime(2014, 8, 14, 19, 25, 6), datetime.datetime(2014, 8, 14, 19, 25, 7), datetime.datetime(2014, 8, 14, 19, 25, 9)] # length 38802
[datetime.datetime(2014, 8, 14, 19, 25, 6), datetime.datetime(2014, 8, 14, 19, 25, 7), datetime.datetime(2014, 8, 14, 19, 25, 9)] # length 40415
I've made a list of these lists called times. I've tried 2 methods of intersecting.
Method 1:
intersection = times[0] # make intersection the first list
for i in range(len(times)):
if i == 0:
continue
intersection = [val for val in intersection if val in times[i]]
This method results in a list with length 20189 and takes 104 seconds to run.
Method 2:
intersection = times[0] # make intersection the first list
for i in range(len(times)):
if i == 0:
continue
intersection = list(set(intersection) & set(times[i]))
This method results in a list with length 20148 and takes 0.1 seconds to run.
I've run into 2 problems with this. The first problem is that the two methods yield different size intersections and I have no clue why. And the other problem is that the datetime object datetime.datetime(2014, 8, 14, 19, 25, 6) is clearly in all 5 lists (see above) but when I print (datetime.datetime(2014, 8, 14, 19, 25, 6) in intersection) it returns False.
Your first list times[0] has duplicate elements; this is the reason for inconsistency. If you would do intersection = list(set(times[0])) in your first snippet, the problem would go away.
As for your second code, the code will be faster if you never do changes between lists and sets:
intersection = set(times[0]) # make a set of the first list
for timeset in times[1:]:
intersection.intersection_update(timeset)
# if necessary make into a list again
intersection = list(intersection)
And actually since intersection supports multiple iterables as separate arguments. you can simply replace all your code with:
intersection = set(times[0]).intersection(*times[1:])
For the in intersection problem, is the instance an actual datetime.datetime or just pretending to be? At least the timestamps seem not to be timezone aware.
Lists can have duplicate items, which can cause inconsistencies with the length. To avoid these duplicates, you can turn each list of datetimes into a set:
map(set, times)
This will give you a list of sets (with duplicate times removed). To find the intersection, you can use set.intersection:
intersection = set.intersection(*map(set, times))
With your example, intersection will be this set:
set([datetime.datetime(2014, 8, 14, 19, 25, 9), datetime.datetime(2014, 8, 14, 19, 25, 6), datetime.datetime(2014, 8, 14, 19, 25, 7)])
There might be duplicated times and you can do it simply like this:
Python3:
import functools
result = functools.reduce(lambda x, y: set(x) & set(y), times)
Python2:
result = reduce(lambda x, y: set(x) & set(y), times)
intersection = set(*times[:1]).intersection(*times[1:])

Categories