Related
I have tried two methods of creating groups of numbers and then dividing those groups into smaller groups of sequential numbers and selecting one.
The first method used lists, but they wouldn't divide the groups correctly.
# This program prints the wrong number of elements.
# I need the correct number of elements, and I want the list to
# deal with floats.
begin = 1
end = 22
num_groop = 2
num_in_groop = (begin + end) // num_groop
lis = []
# loop iterates through index making list from beginning to end
end = num_in_groop
for _ in np.arange(num_groop):
lis.append(list(np.arange(begin, end+1)))
begin += num_in_groop
end += num_in_groop
print('lis', lis,)
# a function to choose one group from the lis and print it
x_1 = lis[0]
x_2 = lis[1]
inp = input('Choose group 1 or 2 by entering 1 or 2\n')
intinp = int(inp)
def choosefunc():
if intinp == 1:
del x_2[:]
print('You chose group x_1 = ',x_1[:])
elif intinp == 2:
del x_1[:]
print('You chose group x_2 = ',x_2[:])
choosefunc()
print('lis is now', lis)
The problem with this is that when it's repeated to narrow down the groups, it divides only using integers. Though the original max number was 22, after repeating this twice, it produces the wrong number of lists. To be correct maths, it should be this:
The first division of the list into an even number is fine:
[[1,2,3,4,5,6,7,8,9,10,11], [12,13,14,15,16,17,18,19,20,21,22]].
Then when choosing one of these groups, choose the first, and divide by two again that's where the maths doesn't work. It should be this:
lis [[1, 2, 3, 4, 5, 5.5], [5.6, 7, 8, 9, 10, 11]]
But because it doesn't seem to handle floats, it is this:
lis [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]].
That's not correct maths. 22/2 = 11, and 11/2 = 5.5.
I want the lists to be of equal size.
# ---------------------------------------------------
When I try to solve the problem using lists, by using numpy arrays, I get an error that stops me from continuing.
# I tried to solve this problem using array but getting an error.
# TypeError: 'tuple' object cannot be interpreted as an integer.
import numpy as np
begin = 1
end = 22
num_groop = 2
num_in_groop = (begin + end) // num_groop
lis = np.array([])
print('lis is now', lis) # prints the new value for lis
end = num_in_groop
for _ in np.arange(num_groop):
print('line20, lis now', lis)
lis(np.arange(range((begin, end+1)))) #error
begin += num_in_groop
end += num_in_groop
print('lis', lis)
If [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]] is an acceptable split, then
def subdivide_list(a):
midpoint = len(a) // 2
return a[:midpoint], a[midpoint:]
lists = [list(range(1, 12))]
for x in range(3):
print(x, lists)
new_lists = []
for a in lists:
new_lists.extend(subdivide_list(a))
lists = new_lists
does what you want:
0 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]]
1 [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11]]
2 [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
EDIT
This also works for [list(range(1, 23))] (print adjusted to show the lengths of the lists):
0 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]] [22]
1 [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]] [11, 11]
2 [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16], [17, 18, 19, 20, 21, 22]] [5, 6, 5, 6]
I was given this as an exercise. I could of course sort a list by using sorted() or other ways from Python Standard Library, but I can't in this case. I think I'm only supposed to use reduce().
from functools import reduce
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
sorted_arr = reduce(lambda a,b : (b,a) if a > b else (a,b), arr)
The error I get:
TypeError: '>' not supported between instances of 'tuple' and 'int'
Which is expected, because my reduce function inserts a tuple into the int array, instead of 2 separate integers. And then the tuple gets compared to an int...
Is there a way to insert back 2 numbers into the list, and only run the function on every second number in the list? Or a way to swap the numbers with using reduce()?
Documentation says very little about the reduce function, so I am out of ideas right now.
https://docs.python.org/3/library/functools.html?highlight=reduce#functools.reduce
Here is one way to sort the list using reduce:
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
sorted_arr = reduce(
lambda a, b: [x for x in a if x <= b] + [b] + [x for x in a if x > b],
arr,
[]
)
print(sorted_arr)
#[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
At each reduce step, build a new output list which concatenates a list of all of the values less than or equal to b, [b], and a list of all of the values greater than b. Use the optional third argument to reduce to initialize the output to an empty list.
I think you're misunderstanding how reduce works here. Reduce is synonymous to right-fold in some other languages (e.g. Haskell). The first argument expects a function which takes two parameters: an accumulator and an element to accumulate.
Let's hack into it:
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
reduce(lambda xs, x: [print(xs, x), xs+[x]][1], arr, [])
Here, xs is the accumulator and x is the element to accumulate. Don't worry too much about [print(xs, x), xs+[x]][1] – it's just there to print intermediate values of xs and x. Without the printing, we could simplify the lambda to lambda xs, x: xs + [x], which just appends to the list.
The above outputs:
[] 17
[17] 2
[17, 2] 3
[17, 2, 3] 6
[17, 2, 3, 6] 1
[17, 2, 3, 6, 1] 3
[17, 2, 3, 6, 1, 3] 1
[17, 2, 3, 6, 1, 3, 1] 9
[17, 2, 3, 6, 1, 3, 1, 9] 5
[17, 2, 3, 6, 1, 3, 1, 9, 5] 3
As we can see, reduce passes an accumulated list as the first argument and a new element as the second argument.(If reduce is still boggling you, How does reduce work? contains some nice explanations.)
Our particular lambda inserts a new element into the accumulator on each "iteration". This hints at insertion sort:
def insert(xs, n):
"""
Finds first element in `xs` greater than `n` and returns an inserted element.
`xs` is assumed to be a sorted list.
"""
for i, x in enumerate(xs):
if x > n:
return xs[:i] + [n] + xs[i:]
return xs + [n]
sorted_arr = reduce(insert, arr, [])
print(sorted_arr)
This prints the correctly sorted array:
[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
Note that a third parameter to reduce (i.e. []) was specified as we initialise the sort should with an empty list.
Ninjad! But yes, it's an insertion sort.
def insert(acc, e):
for i, x in enumerate(acc):
if x > e:
acc.insert(i, e)
return acc
acc.append(e)
return acc
reduce(insert, [1, 2, 6, 4, 7, 3, 0, -1], [])
outputs
[-1, 0, 1, 2, 3, 4, 6, 7]
After some thinking I concluded that it is also possible to do swap-based sort, if you are allowed to use reduce more than once. Namely:
from functools import reduce
arr = [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
def func(acc,x):
if not acc:
return [x]
if acc[-1]<x:
return acc+[x]
else:
return acc[:-1]+[x]+acc[-1:]
def my_sort(x):
moresorted = reduce(func,x,[])
print(moresorted)
if x==moresorted:
return moresorted
else:
return my_sort(moresorted)
print('arr:',arr)
arr_sorted = my_sort(arr)
print('arr sorted:',arr_sorted)
Output:
arr: [17, 2, 3, 6, 1, 3, 1, 9, 5, 3]
[2, 3, 6, 1, 3, 1, 9, 5, 3, 17]
[2, 3, 1, 3, 1, 6, 5, 3, 9, 17]
[2, 1, 3, 1, 3, 5, 3, 6, 9, 17]
[1, 2, 1, 3, 3, 3, 5, 6, 9, 17]
[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
[1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
arr sorted: [1, 1, 2, 3, 3, 3, 5, 6, 9, 17]
I placed print(moresorted) inside func for educational purposes, you could remove it if you wish.
Now explanation: my_sort is recursive function, with every run of it list become more and more sorted. func which is used as function in reduce does append new element and then swaps 2 last elements of list if they are not in ascending order.
This mean in every run of my_sort number "travels" rightward until in take place where next number is bigger.
if not acc is required for starting - notice that third argument of reduce is [] meaning that during first execution of func in each reduce first argument for func is [], so asking acc[-1]<x? would result in error.
Let's understand this
(1)Usage of Reduce is basically to reduce the expression to a single final value
(2)reduce() stores the intermediate result and only returns the final summation value
(3)We will take the smallest element using reduce, append it to sorted_list and remove from the original list
(4)Now the reduce will work on the rest of the elements and repeat step 3 again
(5)while list_nums: will run until the list becomes empty
list_of_nums = [1,19,5,17,9]
sorted_list=[]
while list_of_nums:
maxvalue=reduce(lambda x,y: x if x<y else y,list_of_nums)
sorted_list.append(maxvalue)
list_of_nums.remove(maxvalue)
print(sorted_list)
[1, 5, 9, 17, 19]
For example we have [0, 1, 3, 5, 7, 8, 9, 10, 12, 13] .
The result must be 7, 8, 9, 10 because they are adjacent to each other, index wise and are consecutive integers, and also this chain is longer than 0, 1.
English is not my first language, excuse me if the writing is a bit obscure.
Group the items into subsequences using itertools.groupby based on constant differences from an increasing count (provided by an itertools.count object), and then take the longest subsequence using the built-in max on key parameter len:
from itertools import groupby, count
lst = [0, 1, 3, 5, 7, 8, 9, 10, 12, 13]
c = count()
val = max((list(g) for _, g in groupby(lst, lambda x: x-next(c))), key=len)
print(val)
# [7, 8, 9, 10]
You may include the group key in the result (suppressed as _) to further understand how this works.
Alternative solution using numpy module:
import numpy as np
nums = np.array([0, 1, 3, 5, 7, 8, 9, 10, 12, 13])
longest_seq = max(np.split(nums, np.where(np.diff(nums) != 1)[0]+1), key=len).tolist()
print(longest_seq)
The output:
[7, 8, 9, 10]
np.where(np.diff(nums) != 1)[0]+1 - gets the indices of elements on which the array should be split (if difference between 2 consequtive numbers is not equal to 1, e.g. 3 and 5)
np.split(...) - split the array into sub-arrays
https://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.diff.html#numpy.diff
https://docs.scipy.org/doc/numpy-dev/reference/generated/numpy.split.html
Code
Using itertools.groupby (similar to #Moses Koledoye's answer):
groups = [[y[1] for y in g] for k, g in itertools.groupby(enumerate(iterable), key=lambda x: x[0]-x[1])]
groups
# [[0, 1], [3], [5], [7, 8, 9, 10], [12, 13]]
max(groups, key=len)
# [7, 8, 9, 10]
Alternative
Consider the third-party tool more_itertools.consecutive_groups:
import more_itertools as mit
iterable = [0, 1, 3, 5, 7, 8, 9, 10, 12, 13]
max((list(g) for g in mit.consecutive_groups(iterable)), key=len)
# [7, 8, 9, 10]
I'm trying to plot the output of my function into a list so I can plot it as a graph. My code so far is
t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def anninos():
for time in t:
tfac = math.factorial(time)
print(tfac)
anninos()
The output I get is
1
2
6
24
120
720
5040
40320
362880
3628800
but the output I want is
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
What code do I need to add to get this?
You could use a list comprehension or map() to construct a list:
>>> import math
>>> t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [math.factorial(time) for time in t]
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
>>> list(map(math.factorial, t))
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
You could then return the list from your function or print it.
You could use yield instead of print and do print(list(anninos())) instead of anninos(). You could also construct a list and append to it:
def anninos():
result = []
for time in t:
result.append(math.factorial(time))
print(result)
Whenever you have a loop that just creates a list of the same things, you can use a list comprehension:
def anninos():
print([math.factorial(time) for time in t])
You need use yield or not use funtion. You don't even use the return from a function - why do you use function?:
import math
t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def anninos(values_list):
for time in values_list:
yield math.factorial(time)
print list(anninos(t))
t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
def anninos():
out = []
for time in t:
tfac = math.factorial(time)
out.append(tfac)
print(out)
anninos()
I am trying to come up with a function to split the length of a list evenly depending on it's original length.
So for example if I have a dataset returned that is 2000 I would like to split it into 4. Whereas if the dataset is 1500 split it into 3.
Then to call the function:
Thread_A_DATA, Thread_B_DATA = split_list( SQL_RETURN )
I would like to do something like the following:
if len(dataset) <= 1000:
# Split in 2
a, b = split_list(dataset, 2)
if len(dataset) > 1000 or len(dataset) <= 1500:
# Split in 3
a, b, c = split_list(dataset, 3)
# etc etc...
I've managed to split a dataset in half using this code found previously on stackoverflow:
def split_list( a_list ):
half = len( a_list ) / 2
return a_list[:half], a_list[half:]
But I can't work it out with 3,4 or 5 splits!
If anyone can help that would be great.
Thanks in advance.
As I understand the question, you don't want to split every 500 elements but instead split in 2 if there are less than 1000 elements, in 3 if less than 1500, 4 for 2000, etc. But if there are 1700 elements, you would split in 4 groups of 425 elements (that's what I understand by "split evenly").
So, here's my solution:
def split_list(a_list, number_of_splits):
step = len(a_list) / number_of_splits + (1 if len(a_list) % number_of_splits else 0)
return [a_list[i*step:(i+1)*step] for i in range(number_of_splits)]
l = [1, 8, 2, 3, 4, 5, 6, 7, 1, 5, 3, 1, 2, 5]
print l
print split_list(l, 3)
print split_list(l, 2)
Output
[1, 8, 2, 3, 4, 5, 6, 7, 1, 5, 3, 1, 2, 5]
[[1, 8, 2, 3, 4], [5, 6, 7, 1, 5], [3, 1, 2, 5]]
[[1, 8, 2, 3, 4, 5, 6], [7, 1, 5, 3, 1, 2, 5]]
edit: Python 3 version:
def split_list(a_list, number_of_splits):
step = len(a_list) // number_of_splits + (1 if len(a_list) % number_of_splits else 0)
return [a_list[i*step:(i+1)*step] for i in range(number_of_splits)]
l = [1, 8, 2, 3, 4, 5, 6, 7, 1, 5, 3, 1, 2, 5]
print(l)
print(split_list(l, 3))
print(split_list(l, 2))
Python 3
def splitList(L):
return[L[i:i+500] for i in range(0, len(L), 500)]
Python 2
def splitList(L):
return[L[i:i+500] for i in xrange(0, len(L), 500)]
def split_it(a_list,size_of_split):
return zip(*[iter(a_list)]*size_of_split)
is fun
print split_it(range(100),3) # splits it into groups of 3
unfortunatly this will truncate the end of the list if it does not divide evenly into split_size ... you can fix it like so
return zip(*[iter(a_list)]*size_of_split) + [tuple(a_list[-(len(a_list)%size_of_split):])]
if you wanted to cut it into 7 pieces say you can find the size of the split by
split_size = len(a_list) / num_splits
Python 2.7
>>> import math
>>> lst = range(35)
>>> t = 3 # how many items to be splited
>>> n = int(math.ceil(len(lst) / float(t)))
>>> res = [lst[i:i+n] for i in range(0, len(lst), n)]
>>> res
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23], [24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34]]