In Python, construct cyclic subgroup from generator - python

Using addition in Z modulo 12, (a.k.a the integers mod 12, a.k.a 0 thru 11):
1 generates [0,1,2,3,4,5,6,7,8,9,10,11]
(starting at 0 and repeatedly adding 1; 11+1 takes us back to 0)
In the same way:
2 generates [0,2,4,6,8,10]
3 generates [0 3 6 9]
9 generates [0,9,6,3] <-- notice order is important
How can I create the subgroup given a particular generator?

I'm assuming you mean the additive subgroup Z * g where Z is the set of integers. If you want the precise order, just compute it:
def subgroup(n, g):
x = 0
while True:
yield x
x = (x + g) % n
if x == 0:
break
And of course if order is unimportant, the subgroup induced by g is
{ G * k for k in xrange((n - 1) // G + 1) }
for G = gcd(g, n).

You can create an generator that does what you're asking like this:
from itertools import imap, count
def subgroup(step, start=0, modulo=12):
yield start
for z in imap(lambda x: x%modulo, count(start+step, step)):
if z == start:
return
else:
yield z
Output:
>>> list(subgroup(9))
[0, 9, 6, 3]
>>> list(subgroup(3))
[0, 3, 6, 9]
>>> list(subgroup(2))
[0, 2, 4, 6, 8, 10]
It will keep generating the next item in the sequence until the start is repeated.

Related

Seating arrangement - How do i pick only the neighbors combinations

i used itertools.combinations to list all possible combinations of a list...but how do i pick only the neighbors so that the users are all together
list =[1,2,3,4,5,6,7,8,9,10,11,12]
occupied = [2,6,7,11]
remaining seats are available... Now how do i arrange two folks together always in the available seats..
1 0
3 4
5 0
0 8
9 10
0 12
the right combinations are (1,3) (3,4) (3,5) (8,9) (9,10) (10,12) (since its two folks..we can interchange them.. so two possible ways)... altogether at the moment i have 28...how do i remove the rest..any guidance would be appreciated
/*just added my code/
import numpy as np
import itertools
from itertools import permutations, combinations, combinations_with_replacement
def seatingarrangement (arr):
arry = arr.split(',')
larr = [int(x) for x in arry]
total = (larr[0])
occ = larr[1:]
totals = [x+1 for x in range(0,total)]
print(totals)
for val in totals:
if val in occ:
item= totals.index(val)
totals[item] = 0
print(totals)
#result = list(filter(lambda x: x!=0, totals))
result = [x for x in totals if x != 0]
print(result)
comb = combinations(result,2)
data = itertools.dropwhile(lambda x: x < 5, [3, 12, 7, 1, -5])
print(list(comb))
avl = []
#total there are 8 seats and two users are to be seated next to each other always ... #moreover the seats are not all consecutive
for i,x in enumerate(totals):
if (i+1)%2 == 0:
print('even#:',i+1,'is :',x)
data = itertools.dropwhile()
print(data)
else:
print('odd#:',i+1,'is :',x)
I'd suggest a method that verifies the validity of a pair, regarding the occupied list and the position
def is_pair_valid(pair, occupied_list):
# check occupied
x, y = min(pair), max(pair)
if x in occupied_list or y in occupied_list:
return False
# check neighbours
diff = y - x
return diff in (2, 1, -2) if x % 2 == 1 else diff in (2, -1, -2)
odd number : the other should be at distance +2, +1 or -2 (ex 3 with 1,4,5)
even number : the other should be at distance +2, -1 or -2 (ex 4 with 2,3,6)
Then
values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
occupied = [2, 6, 7, 11]
for p in filter(lambda x: is_pair_valid(x, occupied), combinations(values, r=2)):
print(p)
Gives the correct
(1, 3)
(3, 4)
(3, 5)
(8, 10)
(9, 10)
(10, 12)

Finding last digit of sum from m to n Fibonacci numbers. (0 ≤ 𝑚 ≤ 𝑛 ≤ 10^14)

My code is as follow :
m, n = map(int, input().split())
# write function "fibtotal" which takes input x and gives accurate fib(x+2)%10 (as sum till fib(x) == fib(x+2) - 1)
# using above function get fibtotal(m-1) and fibtotal(n)
# subtract fibtotal(m-1) from fibtotal(n) and do mod 10 gives last digit of sum from m to n
# take care of handling large input sizes, 0 ≤ 𝑚 ≤ 𝑛 ≤ 10^14
def fibtotal(x):
sum = 1 # if both initial conditions fail then loop starts from 2
x= x % 60 # pisano period of 10 is 60 and to get last digit we need to divide by 10
if x == 0:
sum = 1 # fib(2)
return sum
if x == 1:
sum = 2 # fib(3)
return sum
a, b = 0, 1
for i in range(2, x+3): # to find sum till fib(x+2)
c = (a+b)%10
sum += c
a, b = b%10, c%10
return sum%10
# no need to subtract 1 from both as they cancel out
print(fibtotal(n)-fibtotal(m-1))
Following Cases fail using this algorithm:
10 10
My output: 4, correct output: 5
10 200
My output: 5, correct output: 2
1234 12345
My output: 2, correct output: 8
(and possibly many more)
I want to know where is the problem and how can I fix it?
Is there any better approach using same fundamentals?
There is a problem in the number of loop: you do x+1 loops where there should be x. And I don't understand why you don't start with sum = 0.
Then, you can make use of the period to compute the sum in constant time, without any loop. The aux list was computed using fibtotal1.
def fib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a
def fibtotal1(n):
return sum(fib(k) % 10 for k in range(n + 1)) % 10
def fibtotal2(n):
s, a, b = 0, 0, 1
for i in range(n % 60):
a, b = b, a + b
s += a
return s % 10
aux = [0, 1, 2, 4, 7, 2, 0, 3, 4, 8, 3, 2, 6, 9, 6, 6, 3, 0, 4, 5,
0, 6, 7, 4, 2, 7, 0, 8, 9, 8, 8, 7, 6, 4, 1, 6, 8, 5, 4, 0,
5, 6, 2, 9, 2, 2, 5, 8, 4, 3, 8, 2, 1, 4, 6, 1, 8, 0, 9, 0]
def fibtotal3(n):
return aux[n % 60]
print(all(fibtotal1(n) == fibtotal2(n) == fibtotal3(n) for n in range(1000)))
Note also that in your last step, due to computing mod 10 the difference may be negative, so it should be:
def fibtotal(m, n):
return (fibtotal3(n) - fibtotal3(m - 1)) % 10
For the reader passing by: fibtotal2 and fibtotal3 work because fib(n) % 10 is periodic with period 60, and the sum of the elements of the period is a multiple of 10. See Fibonacci's final digits cycle every 60 numbers on Math.SE.
As Jean-Claude mentioned above, there were two main errors
no. of times the loop run
Ideally, the loop should run x times(including conditions), but I confused it with sum(fib(0 to x)) = fib(x+2) -1 and made it run x+2 times
needless %10 at many places
The only place where mod 10 was necessary was at the last statement while displaying the final result. The cause of this error was too much focus on handling large input sizes but they were already handled doing x%60.
The same rectified code looks like:
m, n = map(int, input().split())
def fibtotal(x):
sum = 1 # if both initial conditions fail then loop starts from 2
x= x % 60 # pisano period of 10 is 60 and to get last digit we need to divide by 10
if x == 0:
sum = 1 # fib(2)
return sum
if x == 1:
sum = 2 # fib(3)
return sum
a, b = 0, 1
for i in range(2, x+1): # to find sum till fib(x+2)
c = a+b
sum += c
a, b = b, c
return sum
# no need to subtract 1 from both as they cancel out
print((fibtotal(n)-fibtotal(m-1))%10)
NOTE: the value "sum" doesn't matter if m > 1 as it cancels out while subtracting at last

Get Indices To Split NumPy Array

Let's say I have a NumPy array:
x = np.array([3, 9, 2, 1, 5, 4, 7, 7, 8, 6])
If I sum up this array, I get 52. What I need is a way to split it up starting from left to right into roughly n chunks where n is chosen by the user. Essentially, the splits occur in a greedy fashion. So, for some number of chunks n, the first n - 1 chunks must each sum up to at least 52/n and they must be consecutive indices taken from left to right.
So, if n = 2 then the first chunk would consist of the first 7 elements:
chunk[0] = x[:7] # [3, 9, 2, 1, 5, 4, 7], sum = 31
chunk[1] = x[7:] # [7, 8, 6], sum = 21
Notice that the first chunk wouldn't consist of the first 6 elements only since the sum would be 24 which is less than 52/2 = 26. Also, notice that the number of elements in each chunk is allowed to vary as long as the sum criteria is met. Finally, it is perfectly fine for the last chunk to not be close to 52/2 = 26 since the other chunk(s) may take more.
However, the output that I need is a two column array that contains the start index in the first column and the (exclusive) stop index in the second column:
[[0, 7],
[7, 10]]
If n = 4, then the first 3 chunks need to each sum up to at least 52/4 = 13 and would look like this:
chunk[0] = x[:3] # [3, 9, 2], sum = 14
chunk[1] = x[3:7] # [1, 5, 4], sum = 17
chunk[2] = x[7:9] # [7, 8], sum = 15
chunk[3] = x[9:] # [6], sum = 6
And the output that I need would be:
[[0, 3],
[3, 7],
[7, 9],
[9, 10]
So, one naive approach using for loops might be:
ranges = np.zeros((n_chunks, 2), np.int64)
ranges_idx = 0
range_start_idx = start
sum = 0
for i in range(x.shape[0]):
sum += x[i]
if sum > x.sum() / n_chunks:
ranges[ranges_idx, 0] = range_start_idx
ranges[ranges_idx, 1] = min(
i + 1, x.shape[0]
) # Exclusive stop index
# Reset and Update
range_start_idx = i + 1
ranges_idx += 1
sum = 0
# Handle final range outside of for loop
ranges[ranges_idx, 0] = range_start_idx
ranges[ranges_idx, 1] = x.shape[0]
if ranges_idx < n_chunks - 1:
left[ranges_idx:] = x.shape[0]
return ranges
I am looking for a nicer vectorized solution.
I found inspiration in a similar question that was answered:
def func(x, n):
out = np.zeros((n, 2), np.int64)
cum_arr = x.cumsum() / x.sum()
idx = 1 + np.searchsorted(cum_arr, np.linspace(0, 1, n, endpoint=False)[1:])
out[1:, 0] = idx # Fill the first column with start indices
out[:-1, 1] = idx # Fill the second column with exclusive stop indices
out[-1, 1] = x.shape[0] # Handle the stop index for the final chunk
return out
Update
To cover the pathological case, we need to be a little more precise and do something like:
def func(x, n, truncate=False):
out = np.zeros((n_chunks, 2), np.int64)
cum_arr = x.cumsum() / x.sum()
idx = 1 + np.searchsorted(cum_arr, np.linspace(0, 1, n, endpoint=False)[1:])
out[1:, 0] = idx # Fill the first column with start indices
out[:-1, 1] = idx # Fill the second column with exclusive stop indices
out[-1, 1] = x.shape[0] # Handle the stop index for the final chunk
# Handle pathological case
diff_idx = np.diff(idx)
if np.any(diff_idx == 0):
row_truncation_idx = np.argmin(diff_idx) + 2
out[row_truncation_idx:, 0] = x.shape[0]
out[row_truncation_idx-1:, 1] = x.shape[0]
if truncate:
out = out[:row_truncation_idx]
return out
Here is a solution that doesn't iterate over all elements:
def fun2(array, n):
min_sum = np.sum(array) / n
cumsum = np.cumsum(array)
i = -1
count = min_sum
out = []
while i < len(array)-1:
j = np.searchsorted(cumsum, count)
out.append([i+1, j+1])
i = j
if i < len(array):
count = cumsum[i] + min_sum
out[-1][1] -= 1
return np.array(out)
For the two test cases it produces the results you expected. HTH

constructing arithmetic progressions from loop

I am trying to work out a program that would calculate the diagonal coefficients of pascal's triangle.
For those who are not familiar with it, the general terms of sequences are written below.
1st row = 1 1 1 1 1....
2nd row = N0(natural number) // 1 = 1 2 3 4 5 ....
3rd row = N0(N0+1) // 2 = 1 3 6 10 15 ...
4th row = N0(N0+1)(N0+2) // 6 = 1 4 10 20 35 ...
the subsequent sequences for each row follows a specific pattern and it is my goal to output those sequences in a for loop with number of units as input.
def figurate_numbers(units):
row_1 = str(1) * units
row_1_list = list(row_1)
for i in range(1, units):
sequences are
row_2 = n // i
row_3 = (n(n+1)) // (i(i+1))
row_4 = (n(n+1)(n+2)) // (i(i+1)(i+2))
>>> def figurate_numbers(4): # coefficients for 4 rows and 4 columns
[1, 1, 1, 1]
[1, 2, 3, 4]
[1, 3, 6, 10]
[1, 4, 10, 20] # desired output
How can I iterate for both n and i in one loop such that each sequence of corresponding row would output coefficients?
You can use map or a list comprehension to hide a loop.
def f(x, i):
return lambda x: ...
row = [ [1] * k ]
for i in range(k):
row[i + 1] = map( f(i), row[i])
where f is function that descpribe the dependency on previous element of row.
Other possibility adapt a recursive Fibbonachi to rows. Numpy library allows for array arifmetics so even do not need map. Also python has predefined libraries for number of combinations etc, perhaps can be used.
To compute efficiently, without nested loops, use Rational Number based solution from
https://medium.com/#duhroach/fast-fun-with-pascals-triangle-6030e15dced0 .
from fractions import Fraction
def pascalIndexInRowFast(row,index):
lastVal=1
halfRow = (row>>1)
#early out, is index < half? if so, compute to that instead
if index > halfRow:
index = halfRow - (halfRow - index)
for i in range(0, index):
lastVal = lastVal * (row - i) / (i + 1)
return lastVal
def pascDiagFast(row,length):
#compute the fractions of this diag
fracs=[1]*(length)
for i in range(length-1):
num = i+1
denom = row+1+i
fracs[i] = Fraction(num,denom)
#now let's compute the values
vals=[0]*length
#first figure out the leftmost tail of this diag
lowRow = row + (length-1)
lowRowCol = row
tail = pascalIndexInRowFast(lowRow,lowRowCol)
vals[-1] = tail
#walk backwards!
for i in reversed(range(length-1)):
vals[i] = int(fracs[i]*vals[i+1])
return vals
Don't reinvent the triangle:
>>> from scipy.linalg import pascal
>>> pascal(4)
array([[ 1, 1, 1, 1],
[ 1, 2, 3, 4],
[ 1, 3, 6, 10],
[ 1, 4, 10, 20]], dtype=uint64)
>>> pascal(4).tolist()
[[1, 1, 1, 1], [1, 2, 3, 4], [1, 3, 6, 10], [1, 4, 10, 20]]

Iterate through each value of list in order, starting at random value

Given the following code:
length = 10
numbers = [x for x in range(length)]
start_index = randint(0,length-1)
# now output each value in order from start to start-1 (or end)
# ex. if start = 3 --> output = 3,4,5,6,7,8,9,0,1,2
# ex if start = 9 ---> output = 9,0,1,2,3,4,5,6,7,8
What is the best / simplest / most pythonic / coolest way to iterate over the list and print each value sequentially, beginning at start and wrapping to start-1 or the end if the random value were 0.
Ex. start = 3 then output = 3,4,5,6,7,8,9,1,2
I can think of some ugly ways (try, except IndexError for example) but looking for something better. Thanks!
EDIT: made it clearer that start is the index value to start at
You should use the % (modulo) operator.
length = 10
numbers = [x for x in range(length)]
start = randint(0, length)
for i in range(length):
n = numbers[(i + start) % length]
print(n)
>>> start = randint(0, len(numbers))
>>> start
1
You can use list slicing then iterate over that
>>> numbers[start:] + numbers[:start]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
You can also use the modulus % operator in a list comprehension
>>> [numbers[i%len(numbers)] for i in range(start, start + len(numbers))]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
What is the best / simplest / most pythonic / coolest way ...
You can use collections.deque and its rotate function, like this
>>> from collections import deque
>>> d = deque(numbers)
>>> d.rotate(-9)
>>> d
deque([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])
>>>
>>> d = deque(numbers)
>>> d.rotate(-2)
>>> d
deque([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
You can try to iterate over the list with simple conditional loops
i = start
while(True):
print i,
if i==numbers[-1]: # If it's the last number
i=numbers[0]
else:
i += 1
if i==start: # One iteration is over
break
This will print 3 4 5 6 7 8 9 0 1 2

Categories