Reorder the Range with specific way - python

I'm looking for a way to reorder the given range to have the first, last, middle one, then the middles of the middles and so on..., If we look at 0-15 range it will be like this: So neighbor members will come only at last iteration.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 15 8 4 12 2 6 10 13 1 3 5 7 9 11 14
Any ideas for a good algorithm?

Here's a solution that uses a queue instead of recursion.
13 and 14 are positioned differently from your example, but if you consistently consider the middle of a even-length list to be the element just after the middle, 14 comes first:
import collections
def reorder(seq):
'''Yield items from seq reordered to http://stackoverflow.com/q/33372753/
seq can be any sequence, eg. a list or a Python 3 range object.
'''
# output first and last element before all the middles
if seq:
yield seq[0]
if len(seq) > 1:
yield seq[-1]
# a queue of range indices (start, stop)
queue = collections.deque([(1, len(seq)-1)])
while queue:
start, stop = queue.popleft()
if start < stop:
middle = (start + stop) // 2
yield seq[middle]
queue.append((start, middle))
queue.append((middle+1, stop))
print(list(reorder(range(16))))
#[0, 15, 8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13]

Related

Python Ruler Sequence Generator

I have been struggling for a long time to figure how to define a generator function of a ruler sequence in Python, that follows the rules that the first number of the sequence (starting with 1) shows up once, the next two numbers will show up twice, next three numbers will show up three times, etc.
So what I am trying to get is 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7 etc.
I understand that the way to do this is to have two separate count generators (itertools.count(1)) and then for every number in one generator yield number from the other generator:
def rul():
num = itertools.count(1)
repeator = itertools.count(1)
for x in range(next(repeator)):
yield from num
But if I hit next() on this function, I get back just the regular 1,2,3,4.. sequence...
Any help on this would be appreciated.
how about regular old python with no itertools?
def ruler():
counter = 1
n = 1
while True:
for i in range(counter):
for j in range(counter):
yield n
n += 1
counter += 1
in my humble opinion this is the clearest and most straighforward solution for these types of situations
How about itertools.repeat?
import itertools
def ruler():
num = rep_count = 0
while True:
rep_count += 1
for i in range(rep_count):
num += 1
yield from itertools.repeat(num, rep_count)
You can obtain such a generator without writing your own function using count() and repeat() from itertools:
from itertools import repeat,count
i = count(1,1)
rul = (n for r in count(1,1) for _ in range(r) for n in repeat(next(i),r))
for n in rul: print(n, end = " ")
# 1 2 2 3 3 4 4 4 5 5 5 6 6 6 7 7 7 7 8 8 8 8 9 9 9 9 10 10 10 10 11 11 ...
If you want to go all in on itertools, you'll need count, repeat, and chain.
You can group the numbers in your sequence as follows, with
each group corresponding to a single instance of repeat:
1 # repeat(1, 1)
2 2 # repeat(2, 2)
3 3 # repeat(3, 2)
4 4 4 # repeat(4, 3)
5 5 5 # repeat(5, 3)
6 6 6 # repeat(6, 3)
7 7 7 7 # repeat(7, 4)
...
So we can define ruler_numbers = chain.from_iterable(map(repeat, col1, col2)), as long as we can define col1 and col2 appropriately.
col1 is easy: it's just count(1).
col2 is not much more complicated; we can group them similarly to the original seqeunce:
1 # repeat(1, 1)
2 2 # repeat(2, 2)
3 3 3 # repeat(3, 3)
4 4 4 4 # repeat(4, 4)
...
which we can also generate using chain.from_iterable and map:
chain.from_iterable(map(repeat, count(1), count(1))).
In the end, we get our final result in our best attempt at writing Lisp in Python :)
from itertools import chain, repeat, count
ruler_numbers = chain.from_iterable(
map(repeat,
count(1),
chain.from_iterable(
map(repeat,
count(1),
count(1)))))
or if you want to clean it up a bit with a helper function:
def concatmap(f, *xs):
return chain.from_iterable(map(f, *xs))
ruler_numbers = concatmap(repeat,
count(1),
concatmap(repeat,
count(1),
count(1)))

Python: Find maximum element index in a list

I have a list
arr = [0, 1, 45, 2, 40, 3, 70, 4, 45, 5, 6, 7, 8, 9]
in which I'm trying to find the position/index of the maximum element from 3 consecutive elements using below code:
for i in range (0, len(arr)-3):
print(arr.index(max(arr[i : i+3])))
When i goes to position 7, it gives incorrect result.
Result should be:
2 2 2 4 6 6 6 8 8 11 12
But is instead
2 2 2 4 6 6 6 2 2 11 12
That's because there's two 45's and index returns the first occurrence. You can pass a start and end argument to tell the index method from which indices to start looking from.
for i in range (0, len(arr)-3):
print(arr.index(max(arr[i : i+3]), i, i+3))
Or alternatively:
for i in range (0, len(arr)-3):
sliced_array = arr[i : i+3]
print(i + sliced_array.index(max(sliced_array)))

How can I split my array to small arrays with 10 elements and shift 2 elements each time?

I am trying to split my array that is composed by 100 elements to small arrays each one has 10 elements and calculate their average (the average of each small array). My problem is that each time I want to shift two elements, is what I am doing in the next code is correct ?
Avg_Arr=[sum(Signal[k:k+10])/10 for k in range(0,N,2)]
More precisely, if my Array is the following
Array=[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 .....]
My first small array is
My_Array1=[0 1 2 3 4 5 6 7 8 9]
==> average is (0+1+2+3+4+5+6+7+8+9)/10
while my second one must be
My_Array2=[2 3 4 5 6 7 8 9 10 11]
This should works:
Signal=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]
N = len(Signal)
Avg_Arr=[sum(Signal[k:k+10])/10 for k in range(0, N-10, 2)]
print(Avg_Arr)
Beware that you must stop 10 elements from the end. Otherwise you are not averaging over 10 elements.

Rearranging numbers from list in python3

Lets say I have an list of numbers
a = [ 1,2,3,4,5,6,7,8,9,10]
and I want to print the output as
1
2 3
4 5 6
7 8 9 10
How can I do it in python3.
My attempt:
a = [1,2,3,4,5,6,7,8,9,10]
for i in a:
print(a[i]," ")
i=i+1
I'm getting IndexError: list index out of range and also I don't know to print 1 element in 1'st row , 2nd and 3rd in second row and so on.
One way to do this in Python 3 is to use islice on an iterator :
from itertools import islice
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
it = iter(a)
print('\n'.join([' '.join([str(u)for u in islice(it, i)])for i in range(1,5)]))
output
1
2 3
4 5 6
7 8 9 10

python printing list items incremented on lines

I am trying to take a user input and print out a list of numbers in a box format onto different lines in python.
right now i have:
horizontalsize = int (input ('please enter horizontal size '))
verticalsize = int (input ('please enter vertical size '))
numbers = horizontalsize * verticalsize
mylist = []
mylist.append(range(1,numbers))
for i in range(1,numbers,horizontalsize):
print (i)
The user will input a height and width and if the height input is 5 and the width input is 3 it should print:
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
right now im currently getting:
1
4
7
10
13
How can i get the rest of the numbers to fill in?
Any help is greatly appreciated!
This should work:
for i in range(1, numbers, horizontalsize):
lst = range(i, i+horizontalsize)
print lst # format is [1,2,3]
print ' '.join(map(str,lst)) # format is "1 2 3"
You can also declare a 2D list by list comprehension, example:
>>> horizontalsize = 3
>>> numbers = 15
>>> ll = [[x for x in range(y,y+horizontalsize)]
for y in range(1,numbers,horizontalsize)]
>>> ll
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12], [13, 14, 15]]
>>> for line in ll:
... print ' '.join(map(str,line))
...
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15
The range() you are using will start at 1, go up to numbers, and increase by horizontalsize each time. You are pulling your values for i directly from that range, so those will be the only values you get. One simple solution is to add a second, nested loop to generate the missing values (between i and i+horizontalsize).
for i in range(1,numbers,horizontalsize):
for j in range(i, i+horizontalsize):
print (j, end=" ")
print() #for the newline after every row
Your loop steps skips all the numbers between 1 and 1+horizontalsize, and you just print that number out (without worrying about putting things on the newline). You either need to insert a nested for loop, or modify your range to go over every number, and then put the newline only after specific ones.
That second solution, which uses modulo operator:
for i in range(1,(numbers+1)):
print(i,end=" ")
if i % horizontalsize == 0:
print()
Which gives me:
1 2 3
4 5 6
7 8 9
10 11 12
13 14 15

Categories