Use clipping or zero padding - python

Write a function that accept an array of N elements, and converts it into a 9-element array. Use clipping or zero padding to obtain the desired output. Care should be taken to place the middle element of the input array as the middle element of output array.
Examples
A = [ 2, 5, 1 ] # N == 3, so zero padding to make the output size 9
output = [0, 0, 0, 2, 5, 1, 0, 0, 0]
A = [ 2, 3, 7, 4 ]
output = [0, 0, 2, 3, 7, 4, 0, 0, 0] or [0, 0, 0, 2, 3, 7, 4, 0, 0] # Because there are two middle elements if N is even
A = [ 1, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1 ] # N == 13, so remove 4 elements (2 at the right, 2 at the left) to make the output size 9
output = [3, 4, 7, 6, 4, 3, 3, 2, 2]
A = [ 1, 2, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1 ]
output = [3, 3, 4, 7, 6, 4, 3, 3, 2] or [3, 4, 7, 6, 4, 3, 3, 2, 2]

Imagine you want an output list of n=9 with zeros padding and an input list A.
Then treat the thing as separate problems:
If len(A) == n return A
If len(A) > n then return the middle n elements of A.
Else return a list that starts with (n - len(A)) // 2 zeros, then A, then ends with n - (n - len(A)) // 2 - len(A) zeros (however much is left over from n elements).
E.g.
def fulllist(A, n):
if len(A) == n:
return A
if len(A) > n:
start = (len(A) - n) // 2
return A[start:start+n]
if len(A) < n:
leftpad = [0] * ((n - len(A)) // 2)
rightpad = [0] * (n - len(leftpad) - len(A))
return leftpad + A + rightpad
This gives the following as output:
>>> fulllist([2, 5, 1], 9)
[0, 0, 0, 2, 5, 1, 0, 0, 0]
>>> fulllist([2, 3, 7, 4], 9)
[0, 0, 2, 3, 7, 4, 0, 0, 0]
>>> fulllist([1, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1], 9)
[3, 4, 7, 6, 4, 3, 3, 2, 2]
>>> fulllist([1, 2, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1], 9)
[3, 3, 4, 7, 6, 4, 3, 3, 2]
The above function was written to match the pseudocode, but it would be better to alter it slightly, eliminating case 1. by treating it as a special case of 2. or 3.. That way the code is shorter, and more important, the function always returns a brand new list in every case instead of sometimes returning a reference to the input list, which could get confused in subsequent code and lead to some bugs. I chose to merge 1. with 2.
def fulllist(A, n):
if len(A) >= n:
start = (len(A) - n) // 2
return A[start:start+n]
else:
leftpad = [0] * ((n - len(A)) // 2)
rightpad = [0] * (n - len(leftpad) - len(A))
return leftpad + A + rightpad
Or you can shorten the code further by abusing the fact that [0] * -1 == [].
def fulllist(A, n):
leftpad = [0] * ((n - len(A)) // 2)
rightpad = [0] * (n - len(leftpad) - len(A))
start = (len(A) - n) // 2 if len(A) > n else 0
contents = A[start:start+n]
return leftpad + contents + rightpad
Although that may be going too far for some and it might make the code harder to understand. I like it though.

you can try something like this:
def padding(arr,n):
diff = abs(n - len(arr))
start, end = int(diff / 2), diff - int(diff / 2)
if len(arr) < n:
for i in range(start):
arr.insert(0,0)
for i in range(end):
arr.append(0)
else:
for i in range(start):
arr.pop(0)
for i in range(end):
arr.pop(-1)
return arr
A = [ 1, 3, 3, 4, 7, 6, 4, 3, 3, 2, 2, 2, 1 ]
print(padding(A,9))

Try -
def padding(l1):
flag = 0
while len(l1)>=9:
if len(l1) == 9:
return l1
if flag %2== 0:
l1.pop()
else:
l1.pop(0)
flag+=1
if len(l1)<9:
iterations = (9- len(l1))//2
for _ in range(iterations):
l1.insert(0,0)
l1.append(0)
if iterations % 2 == 0:
l1.append(0)
return l1
padding(A)

Related

Fast python algorithm to find all possible partitions from a list of numbers that has subset sums equal to given ratios

Say I have a list of 20 random integers from 0 to 9. I want to divide the list into N subsets so that the ratio of subset sums equal to given values, and I want to find all possible partitions. I wrote the following code and got it work for the N = 2 case.
import random
import itertools
#lst = [random.randrange(10) for _ in range(20)]
lst = [2, 0, 1, 7, 2, 4, 9, 7, 6, 0, 5, 4, 7, 4, 5, 0, 4, 5, 2, 3]
def partition_sum_with_ratio(numbers, ratios):
target1 = round(int(sum(numbers) * ratios[0] / (ratios[0] + ratios[1])))
target2 = sum(numbers) - target1
p1 = [seq for i in range(len(numbers), 0, -1) for seq in
itertools.combinations(numbers, i) if sum(seq) == target1
and sum([s for s in numbers if s not in seq]) == target2]
p2 = [tuple(n for n in numbers if n not in seq) for seq in p1]
return list(zip(p1, p2))
partitions = partition_sum_with_ratios(lst, ratios=[4, 3])
print(partitions[0])
Output:
((2, 0, 1, 2, 4, 6, 0, 5, 4, 4, 5, 0, 4, 5, 2), (7, 9, 7, 7, 3))
If you calculate the sum of each subset, you will find the ratio is 44 : 33 = 4 : 3, which are exactly the input values. However, I want the function to work for any number of subsets. For example, I expect
partition_sum_with_ratio(lst, ratios=[4, 3, 3])
to return something like
((2, 0, 1, 2, 4, 6, 0, 5, 4, 4, 3), (5, 0, 4, 5, 2, 7), (9, 7, 7))
I have been thinking about this problem for a month and I found this to be extremely hard. My conclusion is that this problem can only be solved by a recursion. I would like to know if there are any relatively fast algorithm for this. Any suggestions?
Yes, recursion is called for. The basic logic is to do a bipartition into one part and the rest and then recursively split the rest in all possible ways. I've followed your lead in assuming that everything is distinguishable, which creates a lot of possibilities, possibly too many to enumerate. Nevertheless:
import itertools
def totals_from_ratios(sum_numbers, ratios):
sum_ratios = sum(ratios)
totals = [(sum_numbers * ratio) // sum_ratios for ratio in ratios]
residues = [(sum_numbers * ratio) % sum_ratios for ratio in ratios]
for i in sorted(
range(len(ratios)), key=lambda i: residues[i] * ratios[i], reverse=True
)[: sum_numbers - sum(totals)]:
totals[i] += 1
return totals
def bipartitions(numbers, total):
n = len(numbers)
for k in range(n + 1):
for combo in itertools.combinations(range(n), k):
if sum(numbers[i] for i in combo) == total:
set_combo = set(combo)
yield sorted(numbers[i] for i in combo), sorted(
numbers[i] for i in range(n) if i not in set_combo
)
def partitions_into_totals(numbers, totals):
assert totals
if len(totals) == 1:
yield [numbers]
else:
for first, remaining_numbers in bipartitions(numbers, totals[0]):
for rest in partitions_into_totals(remaining_numbers, totals[1:]):
yield [first] + rest
def partitions_into_ratios(numbers, ratios):
totals = totals_from_ratios(sum(numbers), ratios)
yield from partitions_into_totals(numbers, totals)
lst = [2, 0, 1, 7, 2, 4, 9, 7, 6, 0, 5, 4, 7, 4, 5, 0, 4, 5, 2, 3]
for part in partitions_into_ratios(lst, [4, 3, 3]):
print(part)

Developing an indexing scheme for list of all non-decreasing sequences

Suppose that we are considering a sorted list of all non-decreasing sequences with values in the range (1, max_num) and num_slots elements in each sequence, how can I find the index of some given member sequence in O(1) time complexity? I am not actually given the entire list up-front, I just want to find the index of some member sequence were the list of all sequences to exist.
For a concrete example, suppose that max_num = 3 and num_slots = 4. Then there are 15 sequences (or generally, there are (max_num + num_slots - 1) choose (num_slots) sequences):
[[1, 1, 1, 1],
[1, 1, 1, 2],
[1, 1, 1, 3],
[1, 1, 2, 2],
[1, 1, 2, 3],
[1, 1, 3, 3],
[1, 2, 2, 2],
[1, 2, 2, 3],
[1, 2, 3, 3],
[1, 3, 3, 3],
[2, 2, 2, 2],
[2, 2, 2, 3],
[2, 2, 3, 3],
[2, 3, 3, 3],
[3, 3, 3, 3]]
So given inputs of a sequence like [1, 2, 2, 3] along with the information max_num = 3, I am trying to write a function that would return its correct index of 7. I do not actually have the list of all sequences to work with.
Background info
I have come up with an algorithm to generate all non-decreasing sequences I care about, but this doesn't seem completely relevant for generating the index of a particular member sequence without the whole list of sequences materialized.
def gen(max_num, num_slots, l = None):
if l is None:
l = [[1] * num_slots]
cur = l[-1].copy()
for i in reversed(range(num_slots)):
if cur[i] < max_num:
cur[i] += 1
for j in range(i+1, num_slots):
cur[j] = cur[i]
l.append(cur)
return gen(max_num, num_slots, l)
return l
This one is O(|seq| + max_num). Note that this is still much faster than the naive generate all and search approach, which is exponential in |seq|.
The idea is that you count the sequences before the input sequence. For example,
you want to know what's the index of [2, 4, 5, 6] when max_num = 6.
Count [1, *, *, *]
Count [2, 2, *, *]
Count [2, 3, *, *]
(Note: you cannot count [2, 4, *, *], because then you would include [2, 4, 6, 6] which comes after your input. You should always go until one less than your input at the given index)
Count [2, 4, 4, *]
Count [2, 4, 5, 5]
(for each row, you can use your formula, (max_num + num_slots - 1) choose (num_slots) and sum them up)
def combinations(slots, available):
return choose(slots + available - 1, slots)
def find_index(seq, max_num):
res = 0
for digit_index in xrange(len(seq)):
prev = seq[digit_index - 1] if digit_index > 0 else 1
for digit in xrange(prev, seq[digit_index]):
res += combinations(len(seq) - digit_index - 1, max_num - digit + 1)
return res
print find_index([1, 2, 2, 3], 3)
I'll elaborate on #DavidFrank's answer on why it is O(length+max_num) and give a more easily understand example (a bit more complex too).
To start with, observe:
Assume the total series possibility in F(length, max_num) = X
Then for all of possibilities in X that starts with 1, e.g. [1, ....], we have a count of F(length-1, max_num) within this group.
For all the possibility in X that does not start with 1, e.g. [2, ....] or [3, ....], we have a count of F(length, max_num-1).
Thus we can use recursion to get this in O(length*max_num) (can become O(length+max_num) if we use memoization) number of complexity:
# This calculate the total number of X of possible entry given (length, max_num)
def calc_sum(length, max_num):
if max_num == 1:
return 1
elif length == 1:
return max_num
else:
total = calc_sum(length-1, max_num) + calc_sum(length, max_num-1)
return total
Now we examine the result to see if we can make it O(1):
# This is clearly not going to make it O(1), so now we need some generalizations to NOT run this recursion.
import numpy as np
arr = np.zeros((6,6))
for i in range(6):
for j in range(6):
arr[i, j] = calc_sum(i+1, j+1)
print(arr)
The result is:
[[ 1. 2. 3. 4. 5. 6.]
[ 1. 3. 6. 10. 15. 21.]
[ 1. 4. 10. 20. 35. 56.]
[ 1. 5. 15. 35. 70. 126.]
[ 1. 6. 21. 56. 126. 252.]
[ 1. 7. 28. 84. 210. 462.]]
This is a pascal's triangle, if you look diagonally to the top right. The diagonals of pascal's triangle are defined by (x choose y)
This makes it clear that it cannot be O(1), and will at least be O(length+max_num) because this is the general complexity of (Choose) function.
We've went all the way to prove that an O(1) solution is impossible, unless we constrain (length + max_num) to be constant.
# We can expand by solving it now:
from scipy.special import comb # this is choose function.
def get_index(my_list, max_num):
my_list = np.array(my_list)
if len(my_list) == 1:
return my_list[0] - 1
elif my_list[0] == 1:
return get_index(my_list[1:], max_num)
elif my_list[0] != 1:
return get_index(my_list - 1, max_num - 1) + comb(len(my_list)-2+max_num, max_num-1)
get_index([1,2,2,3],3) # 7
The aggregated complexity of the final function with the comb() is still O(length + max_num) as the complexity of everything outside comb is O(length + max_num) as well.
There is bijection from the k-subsets of {1...n} (with repetition) to k-subsets of {1...n + k − 1} (without repetition) by mapping {c_0, c_1...c_(k−1)} to {c_0, c_(1+1), c_(2+2)...c_(k−1+k−1)} (see here).
Once converted, just use your favourite combination ranking utility.
[3, 3, 3, 3] --> [3, 4, 5, 6]
[2, 3, 3, 3] --> [2, 4, 5, 6]
[2, 2, 3, 3] --> [2, 3, 5, 6]
[2, 2, 2, 3] --> [2, 3, 4, 6]
[2, 2, 2, 2] --> [2, 3, 4, 5]
[1, 3, 3, 3] --> [1, 4, 5, 6]
[1, 2, 3, 3] --> [1, 3, 5, 6]
[1, 2, 2, 3] --> [1, 3, 4, 6]
[1, 2, 2, 2] --> [1, 3, 4, 5]
[1, 1, 3, 3] --> [1, 2, 5, 6]
[1, 1, 2, 3] --> [1, 2, 4, 6]
[1, 1, 2, 2] --> [1, 2, 4, 5]
[1, 1, 1, 3] --> [1, 2, 3, 6]
[1, 1, 1, 2] --> [1, 2, 3, 5]
[1, 1, 1, 1] --> [1, 2, 3, 4]
import pyncomb
def convert(m, S):
return (m + len(S) - 1, [ x-1 + i for x,i in zip(S, list(xrange(len(S)))) ])
def rank(m, S):
k, s = convert(m, S)
return pyncomb.ksubsetcolex.rank(k, s)
print rank(3, [1,2,2,3])
# 7
For each digit, find the difference between that and the lowest digit. Add 1 for each changed position to the right of any altered digit
idx = 0;
for i in range(0,num_slots):
d = SEQ[i]
idx += d-min_num
if (d > min_num):
idx += num_slots-1 - i
For example:
[1,1,1,3] is 0 + 0 + 0 + (2+0) or 2
[1,2,3,3] is 0 + (1+2) + (2+1) + (2+0) or 8
[3,3,3,3] is (2+3) + (2+2) + (2+1) + (2+0) or 14

python: how to strip lines efficiently from a matrix, which have elements appearing in other lines

list = [0, 1, 2, 3, 4, 1, 5, 0, 6, 5, 7, 8, 9, 10, 11, 12, 13, 2]
list is used "matrix like"
1. 0 1 2
2. 3 4 1
3. 5 0 6
... and so on. I would like to write all those lines into a new list/matrix, but without lines, that would repeat a number. However the order of a line has to be preserved.
So far I use this:
compa = [0,1,2,3,4,1,5,0,6,5,7,8,9,10,11,12,13,2] #the list to be used as base
temp = [0,1,2] #new list starts from the first element
temp2 = [12,13,2] #new list starts from the last element
Mischzahl = 3 #defines the number of elements in a line of the "matrix"
n = 0
while n < len(compa):
for m in range(0,len(temp)):
if temp[m] == compa[n]:
n = (int(n/Mischzahl) + 1) * Mischzahl - 1 #calculates the "foul" line and sets n to the next line
break
if (n + 1) % Mischzahl == 0 and m == len(temp) - 1 : #if the end of temp is reached, the current line is transferred to temp.
for p in range(Mischzahl):
temp.append(compa[Mischzahl*int(n/Mischzahl) + p])
n += 1
and the same backwards
n = len(compa) - 1
while n > 0: #same as above but starting from last element
for m in range(len(temp2)):
if temp2[m] == compa[n]:
n = (int(n/Mischzahl) - 1) * Mischzahl + Mischzahl
break
if (n) % Mischzahl == 0 and m == len(temp2) - 1:
for p in range(Mischzahl):
temp2.append(compa[Mischzahl*int(n/Mischzahl) + p])
n = n - 1
resulting output for temp and temp2:
[0, 1, 2, 3, 4, 1, 5, 0, 6, 5, 7, 8, 9, 10, 11, 12, 13, 2] #compa
[0, 1, 2, 5, 7, 8, 9, 10, 11] #temp
[12, 13, 2, 9, 10, 11, 5, 7, 8, 3, 4, 1] #temp2
Since this is the most time-consuming part of the script: Is there a more efficient way to do this? Any helpful advice or direction would be highly welcome.
You can define a function that iterates over the list in strides of a given length (in your case 3), checks if the elements of the stride are in a set of numbers, if not extend the out list and update the set.
from math import ceil
def unique_by_row(compa, stride_size=3, reverse=False):
strides = ceil(len(compa)/stride_size)
out = []
check = set()
it = range(strides)
if reverse:
it = reversed(it)
for i in it:
x = compa[stride_size*i:stride_size*(i+1)]
if not check.intersection(x):
out.extend(x)
check.update(x)
return out
Tests:
compa = [0, 1, 2, 3, 4, 1, 5, 0, 6, 5, 7, 8, 9, 10, 11, 12, 13, 2]
unique_by_row(compa)
# returns:
[0, 1, 2, 5, 7, 8, 9, 10, 11]
unique_by_row(compa, reverse=True)
# returns:
[12, 13, 2, 9, 10, 11, 5, 7, 8, 3, 4, 1]

Find 4 numbers which sum is given number

Need to find 4 numbers from list which sum will be equal to given "sum_"
def find_four(nums, sum_):
if len(nums) < 4:
return
i = 0
i2 = 1
i3 = 2
i4 = 3
while True:
num_sum = nums[i] + nums[i2] + nums[i3] + nums[i4]
if num_sum == sum_:
return [nums[i], nums[i2], nums[i3], nums[i4]]
elif i == len(nums) - 4:
return
elif i2 == len(nums) - 3:
i += 1
elif i3 == len(nums) - 2:
i2 += 1
elif i4 == len(nums) - 1:
i3 += 1
elif i4 != len(nums):
i4 += 1
My code works good with some lists like:
find_four([1, 1, 1, 5, 1, 5, 7], 10) or
find_four([4, 6, 1, 4, 1, 6, 2], 13).
But it don't work with some for example'
find_four([7, 5, 1, 4, 1, 6, 2], 11) (need to print 7, 1, 1, 2)
What is wrong ?? :(
There's no reason for nested loops.
import itertools
import operator as op
from functools import reduce
def find_N(nums, target, N=4):
for combo in list(itertools.combinations(nums, N)):
if reduce(op.add, combo) == target:
return combo
return []
>>> find_N([1,2,3,4,5,6,7,8], target=10)
(1, 2, 3, 4)
>>> find_N([1,2,3,4,5,6,7,8], target=10, N=3)
(1, 2, 7)
>>> find_N([1,2,3,4,5,6,7,8], target=10, N=2)
(2, 8)
Observations:
Many things are pre-built in Python, use them instead of recreating the wheel
Generalization is good. You don't want to change your function if N changes from 4
sum isn't a sound variable name as it clobbers the built-in function of that name
You should probably sort nums before processing it in chunks of 4, as you're doing.
def find_four(nums, sum_):
if len(nums) < 4:
return
nums = sorted(nums) # Sort nums here
i = 0
i2 = 1
i3 = 2
i4 = 3
while True:
num_sum = nums[i] + nums[i2] + nums[i3] + nums[i4]
if num_sum == sum_:
return [nums[i], nums[i2], nums[i3], nums[i4]]
elif i == len(nums) - 4:
return
elif i2 == len(nums) - 3:
i += 1
elif i3 == len(nums) - 2:
i2 += 1
elif i4 == len(nums) - 1:
i3 += 1
elif i4 != len(nums):
i4 += 1
This will produce for 7, 1, 1, 2 for find_four([7, 5, 1, 4, 1, 6, 2], 11). Note that the order of the numbers will not be preserved.
Simply use itertools.combinations. Below code will return all pairs from which has summation equals to sum_. I am setting combinations to take 4 numbers by passing 4 default in the argument. You can alternate amount of numbers used for calculating sum by changing target.
import itertools
from itertools import combinations
def find_four(nums, sum_,target=4):
return([pair for pair in itertools.combinations(nums,target) if sum(pair) == sum_])
nums=[1,2,3,4,1,5,6,7,8,9,10,11,12]
example:-
>>> find_four([1,2,3,4,1,5,6,7,8,9,10,11,12],10)
[(1, 2, 3, 4), (1, 2, 1, 6), (1, 3, 1, 5), (2, 3, 4, 1)]
>>>find_four([1,2,3,4,1,5,6,7,8,9,10,11,12],10,3)
[(1, 2, 7), (1, 3, 6), (1, 4, 5), (1, 1, 8), (2, 3, 5), (2, 1, 7), (3, 1, 6), (4, 1, 5)]
You can do this simpler using 4 loops
def find_four(arr, sum_):
for i in range(len(arr)):
for j in range(i + 1, len(arr)):
for t in range(j + 1, len(arr)):
for k in range(t + 1, len(arr)):
if arr[i] + arr[j] + arr[t] + arr[k] == sum_:
return [arr[i],arr[j],arr[t],arr[k]]
return []
Input
find_four([1, 1, 1, 5, 1, 5, 7], 10)
find_four([4, 6, 1, 4, 1, 6, 2], 13)
find_four([7, 5, 1, 4, 1, 6, 2], 11)
Output
[1, 1, 1, 7]
[4, 6, 1, 2]
[7, 1, 1, 2]
I notice that each collection of numbers in the question is a bag or multiset, rather than a set. That is, each collection contains at least one repetition of one of its members. This guaranteed to be the case, it can be more appropriate to calculate all multiset combinations and thereby avoid processing repeated combinations.
>>> from sympy.utilities.iterables import multiset_combinations
>>> def find_four(nums, sum_):
... for c in multiset_combinations(nums, 4):
... if sum(c) == sum_:
... return c
... return {}
...
>>> find_four([1, 1, 1, 5, 1, 5, 7], 10)
[1, 1, 1, 7]
>>> find_four([4, 6, 1, 4, 1, 6, 2], 13)
[1, 2, 4, 6]
>>> find_four([7, 5, 1, 4, 1, 6, 2], 11)
[1, 1, 2, 7]

Algorithm to return a reordered range for data rendering

Here are examples:
given: 1,2,3 [list or range of numbers]
return: 2,1,3 [reordered list]
given: 1,2,3,4,5
return: 3 1 5 2 4
given: 1,2,3,4,5,6,7
return: 4 1 7 2 6 3 5 OR 4 7 1 5 3 2 6 or similar
given: 1,2,4,5,6,7,8,9
return: 5,1,9,3,7,2,8,4,6 or similar
In rendering you start with the center, then the most extreme cases, and become more and more detailed. This is NOT random. I'm in python, but theres got to be a name for this in comp sci. Help appreciated.
Edit to add
even case -
given: 1234
return: 2,1,4,3 OR 3,1,4,2 OR 2,4,1,3 OR 3,4,1,2
A valid, although ungraceful solution:
def sigorder(lst):
result = []
l = len(lst)
if l <= 2:
return lst
if l > 2:
result.append(lst[l/2])
result.append(lst[0])
result.append(lst[-1])
right = sigord(lst[l/2+1:-1])
left = sigord(lst[1:l/2])
result.extend(slicezip(left, right))
return result
Inner, recursive function:
def sigord(lst):
result = []
if len(lst) < 3:
return lst
else:
l = len(lst)
result.append(lst[l/2])
left = sigord(lst[0:l/2])
right = sigord(lst[l/2 + 1:len(lst)])
result.extend(slicezip(left, right))
return result
slicezip() (Note: conveniently handles the potential unevenness of the left/right lists automagically)
def slicezip(a, b):
result = [0]*(len(a)+len(b))
result[::2] = a
result[1::2] = b
return result
Outputs for lists length 4-9 :
[3, 1, 4, 2]
[3, 1, 5, 2, 4]
[4, 1, 6, 2, 5, 3]
[4, 1, 7, 2, 5, 3, 6]
[5, 1, 8, 3, 6, 2, 7, 4]
[5, 1, 9, 3, 7, 2, 6, 4, 8]
This should do it:
def extreme_cases(upd_itrr, new_itrr):
new_itrr.append(min(upd_itrr))
new_itrr.append(max(upd_itrr))
upd_itrr.remove(min(upd_itrr))
upd_itrr.remove(max(upd_itrr))
if len(upd_itrr) >= 2:
extreme_cases(upd_itrr, new_itrr)
return upd_itrr, new_itrr
def reordered_range(itr):
new_itr = []
center = 0
if len(itr) % 2 != 0:
center = itr[len(itr) // 2]
elif len(itr) % 2 == 0:
center = itr[(len(itr) // 2) - 1]
new_itr.append(center)
upd_itr = itr[:]
upd_itr.remove(center)
upd_itr, new_itr = extreme_cases(upd_itr, new_itr)
if upd_itr:
new_itr.append(upd_itr[0])
return new_itr
print(reordered_range([1, 2, 3]))
print(reordered_range([1, 2, 3, 4]))
print(reordered_range([1, 2, 3, 4, 5]))
print(reordered_range([1, 2, 3, 4, 5, 6, 7]))
print(reordered_range([1, 2, 4, 5, 6, 7, 8, 9]))
Output:
[2, 1, 3]
[2, 1, 4, 3]
[3, 1, 5, 2, 4]
[4, 1, 7, 2, 6, 3, 5]
[5, 1, 9, 2, 8, 4, 7, 6]
Another solution:
import numpy as np
from copy import copy
def bisecting_order(lst):
# bisecting order of an unordered list
result = []
l = len(lst)
if l < 3:
return lst
result.append(closest(lst,np.mean(lst)))
result.append(min(lst))
result.append(max(lst))
# get bisections
while len(result)!=len(lst):
temp_list = copy(result)
temp_list.sort()
for i in xrange(len(temp_list)-1):
newnum = closest(lst,np.mean([temp_list[i],temp_list[i+1]]))
if newnum in result:
continue
else:
result.append(newnum)
return result
def closest(mylist,mynum):
return min(mylist, key=lambda x:abs(x-mynum))

Categories