Seating arrangement - How do i pick only the neighbors combinations - python

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)

Related

Filtering a pair of arrays for a certain range of numbers using python

So let's say I have two arrays x and y.
x = [5, -6, 3, 11, -4, 2]
y = [1, 9, 2, 8, 12, -5]
I need to filter these arrays, keeping only values between 0 and 10. I was able to do this separately:
new_x=[i for i in x if i>=0 and i<=10] with output
[5, 3, 2]
new_y=[i for i in y if i>=0 and i<=10] with output
[1, 9, 2, 8]
However, these x and y arrays are meant to symbolize coordinates, which I will later have to graph. They have to remain in pairs, so if an element in the x array does not fulfill the criteria, I do not want to include the matching y element. Same goes vice versa.
By looking at the arrays, it is easy to tell that only the first and third pair - (5,1) and (3,2) respectively - fulfill my criteria. How can I filter x and y together to represent this? My dataset is much larger than this example, so I do not have the time to filter through it manually.
Any help would be greatly appreciated!
zip them together:
pairs = [(a, b) for a, b in zip(x, y) if 0 <= a <= 10 and 0 <= b <= 10]
# [(5, 1), (3, 2)]
If you then want to go back to x, y (I wouldn't recommend this, just keep them together), you could use:
x, y = zip(*pairs)
Which will return x and y as tuples:
x = (5, 3)
y = (1, 2)
In this context, the two tuples look like ordered pairs, but in general you could get something like
x = (5, 3, -6, 11, ...)
You can use the filter function
filtered_coords = list(
filter(lambda coords: all([0 <= coord <= 10 for coord in coords]), zip(x, y))
)
If you want to split the x and y coordinates:
filtered_x, filtered_y = [[c[i] for c in filtered_coords] for i in range(2)]
print(filtered_x) # [5, 3]
print(filtered_y) # [1, 2]
Use the same index to point to both arrays at the same time.
x = [5, -6, 3, 11, -4, 2]
y = [1, 9, 2, 8, 12, -5]
new_x = []
new_y = []
for i in range(len(x)):
if 0 <= x[i] <= 10 and 0 <= y[i] <= 10:
new_x.append(x[i])
new_y.append(y[i])
print(new_x, new_y)
# [5, 3] [1, 2]

Explain for loop

I was trying the below code. Kindly go through below code and help me understand what is the logic to get the below output.
I was trying to add only the first 10 values or first 9 values out of the given 11 values.
nums = [1,3,5,7,9,1,3,2,4,5,6]
def random(nums):
count = 0
for x in range(len(nums)-2):
count = count + x
return count
print("The random addition for above prog is")
print(random(nums))
output:
The random addition for above prog is
36
when I replaced with for x in range(len(nums)-2) i am getting below o/p
The random addition for above prog is
45
when I replaced with for x in range(len(nums)) i am getting below o/p
The random addition for above prog is
55
on what basis I should use the logic range(len(nums)-2) or range(len(nums)-3) in using the for loop.
You added index value that created by range, not list values.
count += x # this is one of [0,1...]
len and range's behavior is below.
len returns number of value list contains
>>> nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> len(nums)
11
range returns n length list start with 0(usable for list index)
>>> range(11)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
python's for takes one value from list, and do something and take next one value...
for i in [1,3,2]:
print(i)
1
3
2
If you want to take first 10 value of list and loop them, you can do below.
for i in range(10):
print(nums[i])
length of list can create range's arg 10 with below
len(nums) - 1
# => 11 - 1
# => 10
integrate them for first 10 values of list
for i in range(len(nums) - 1):
print(nums[i])
if you want sum random values
count = 0
>>> for i in range(len(nums) - 1):
... print(i, nums[i])
... count += nums[i]
...
(0, 1)
(1, 3)
(2, 5)
(3, 7)
(4, 9)
(5, 1)
(6, 3)
(7, 2)
(8, 4)
(9, 5)
>>> count
40
>>>
If you want to just sum first 10 value of list with loop, you can write below
count = 0
for x in nums[:10]:
count += x
nums[:10] returns list contains first 10 values of nums like [1,3,5,...8]

How can I find the indices of any two of the numbers, whose sum is equal to the target sum in Python?

I'm doing this test on testdome.com for practicing , and it's failing some test case. Can anyone help me pointing out the logic error in my code?
This is the question for my code:
"Write a function that, when passed a list and a target sum, returns, efficiently with respect to time used, two distinct zero-based indices of any two of the numbers, whose sum is equal to the target sum.
If there are no two numbers, the function should return None.
For example, find_two_sum([3, 1, 5, 7, 5, 9], 10) should return a single tuple containing any of the following pairs of indices:
0 and 3 (or 3 and 0) because addition of 3 and 7 is 10.
1 and 5 (or 5 and 1) because addition of 1 and 9 is 10.
2 and 4 (or 4 and 2) because addition of 5 and 5 is 10.
def find_two_sum(numbers, target_sum):
sss=list(dict.fromkeys(numbers))
if (sss == None or len(sss) < 2): return None
for item in sss:
tesn=target_sum-item
if tesn in sss:
if numbers.index(item)==numbers.index(tesn):
continue
else:
return numbers.index(item),numbers.index(tesn)
return None
print(find_two_sum([3, 1, 5, 7, 5, 9], 10))
They have four test cases and my code can only pass first two test cases.
Example case:Wrong answer ( to return [0,2] because 3 of index 0 + 7 of index 3 is 10)
Distinct numbers with and without solutions: Wrong answer
Duplicate numbers with and without solutions: Wrong answer
Performance test with a large list of numbers: Wrong answer
My take on the problem:
def find_two_sum(lst, n):
indices = {}
for idx, num in enumerate(lst):
indices.setdefault(num, []).append(idx)
for k, v in indices.items():
i = v.pop()
if n - k in indices and indices[n-k]:
return i, indices[n-k].pop()
print( find_two_sum([3, 1, 5, 7, 5, 9], 6) )
print( find_two_sum([3, 1, 5, 7, 5, 9], 10) )
print( find_two_sum([1, 2, 1, 8], 10) )
print( find_two_sum([5, 5], 10) )
print( find_two_sum([11], 10) )
Prints:
(1, 4)
(0, 3)
(1, 3)
(1, 0)
None
I believe you have to add a check for the two indexes to be distinct.
For example here:
print(find_two_sum([3, 1, 5, 7, 5, 9], 6))
The function will give an answer of (0, 0) which wouldn't be correct, though these are the indexes of 3, which gives a sum of 6 with itself .
Here, I've added the check for distinct indexes:
def find_two_sum(numbers, target_sum):
sss = list(dict.fromkeys(numbers))
if (sss == None or len(sss) < 2): return None
tup=()
for item in sss:
item_index = numbers.index(item)
tesn = target_sum - item
if tesn in sss:
tesn_index = numbers.index(tesn)
if item_index!=tesn_index:
return (item_index, tesn_index)
return None
One flaw in the logic is that sss does not contain duplicates that may exist in the original list - you have lost information. You are assuming there are no duplicates in the original list: list.index(n) will return the index of the first item equal to n so you can end up with a result with duplicate indices
>>> a = [3, 1, 5, 7, 5, 9]
>>> item = 5
>>> tesn = 5
>>> a.index(item),a.index(tesn)
(2, 2)
>>>
Your algorithm has a flaw e.g. find_two_sum([5, 2], 10) gives (0, 0).
This is because when you check item in sss, it's gonna evaluate to true when item is 5, there is only a single 5 in the input list.
This answer seems to be 50% correct.
def find_two_sum(numbers, target_sum):
for n in numbers:
for i in numbers[numbers.index(n)+1:]:
if n+i==target_sum:
return(numbers.index(n),numbers.index(i))
break
return None
print(find_two_sum([3, 1, 5, 7, 5, 9], 10))

Detect peaks in list of numbers and record their positions

I am trying to create some code that returns the positions and the values of the "peaks" (or local maxima) of a numeric array.
For example, the list arr = [0, 1, 2, 5, 1, 0] has a peak at position 3 with a value of 5 (since arr[3] equals 5).
The first and last elements of the array will not be considered as peaks (in the context of a mathematical function, you don't know what is after and before and therefore, you don't know if it is a peak or not).
def pick_peaks(arr):
print(arr)
posPeaks = {
"pos": [],
"peaks": [],
}
startFound = False
n = 0
while startFound == False:
if arr[n] == arr[n+1]:
n += 1
else:
startFound = True
endFound = False
m = len(arr) - 1
while endFound == False:
if arr[m] == arr[m-1]:
m -= 1
else:
endFound = True
for i in range(n+1, m):
if arr[i] == arr[i-1]:
None
elif arr[i] >= arr[i-1] and arr[i] >= arr[i+1]:
posPeaks["pos"].append(i)
posPeaks["peaks"].append(arr[i])
return posPeaks
My issue is with plateaus. [1, 2, 2, 2, 1] has a peak while [1, 2, 2, 2, 3] does not. When a plateau is a peak, the first position of the plateau is recorded.
Any help is appreciated.
I suggest you use groupby to group contiguous equal values, then for each group store the first position, example for [1, 2, 2, 2, 1] it creates the following list following list of tuples [(1, 0), (2, 1), (1, 4)], putting all together:
from itertools import groupby
def peaks(data):
start = 0
sequence = []
for key, group in groupby(data):
sequence.append((key, start))
start += sum(1 for _ in group)
for (b, bi), (m, mi), (a, ai) in zip(sequence, sequence[1:], sequence[2:]):
if b < m and a < m:
yield m, mi
print(list(peaks([0, 1, 2, 5, 1, 0])))
print(list(peaks([1, 2, 2, 2, 1])))
print(list(peaks([1, 2, 2, 2, 3])))
Output
[(5, 3)]
[(2, 1)]
[]
I know I may be a little late for the party, but I'd like to share my solution using NumPy arrays:
def get_level_peaks(v):
peaks = []
i = 1
while i < v.size-1:
pos_left = i
pos_right = i
while v[pos_left] == v[i] and pos_left > 0:
pos_left -= 1
while v[pos_right] == v[i] and pos_right < v.size-1:
pos_right += 1
is_lower_peak = v[pos_left] > v[i] and v[i] < v[pos_right]
is_upper_peak = v[pos_left] < v[i] and v[i] > v[pos_right]
if is_upper_peak or is_lower_peak:
peaks.append(i)
i = pos_right
peaks = np.array(peaks)
"""
# uncomment this part of the code
# to include first and last positions
first_pos, last_pos = 0, v.size-1
peaks = np.append([first_pos], peaks)
peaks = np.append(peaks, [last_pos])
"""
return peaks
Example 1 (see graph):
v = np.array([7, 2, 0, 4, 4, 6, 6, 9, 5, 5])
p = get_peaks(v)
print(v) # [7 2 0 4 4 6 6 9 5 5]
print(p) # [0 2 7 9] (peak indexes)
print(v[p]) # [7 0 9 5] (peak elements)
Example 2 (see graph):
v = np.array([8, 2, 1, 0, 1, 2, 2, 5, 9, 3])
p = get_peaks(v)
print(v) # [8 2 1 0 1 2 2 5 9 3]
print(p) # [0 3 8 9] (peak indexes)
print(v[p]) # [8 0 9 3] (peak elements)
Example 3 (see graph):
v = np.array([9, 8, 8, 8, 0, 8, 9, 9, 9, 6])
p = get_peaks(v)
print(v) # [9 8 8 8 0 8 9 9 9 6]
print(p) # [0 4 6 9] (peak indexes)
print(v[p]) # [9 0 9 6] (peak elements)
In example 3, we have a flatten upper peak that goes from index 6 to index 8. In this case, the index will always indicate the leftmost position of the plateau. If you want to indicate the middle position or the rightmost position, just change this part of the code:
...
if is_upper_peak or is_lower_peak:
peaks.append(i)
...
to this:
...
# middle position
if is_upper_peak or is_lower_peak:
peaks.append((pos_left + pos_right) // 2)
...
...
# rightmost position
if is_upper_peak or is_lower_peak:
peaks.append(pos_right)
...
This code takes a window number and gives the peak within that window size
l=[1,2,3,4,5,4,3,2,1,2,3,4,3,2,4,2,1,2]
n=int(input("The size of window on either side "))
for i in range(n,len(l)-n):
if max(l[i-n:i]+l[i+1:i+n+1])<l[i]:
print(l[i],' at index = ',i)
You can use the same algorithm with the plateaus as well if you can preprocess the data to remove the repeating numbers and keep only 1 unique number. Thus, you can convert the example [1, 2, 2, 2, 1] to [1, 2, 1] and apply the same algorithm.
Edit:
The Code:
from itertools import groupby
def process_data(data):
return [list(val for num in group) for val, group in groupby(data)]
def peaks(arr):
#print(arr)
posPeaks = {
"pos": [],
"peaks": [],
}
startFound = False
n = 0
while startFound == False:
if arr[n][0] == arr[n+1][0]:
n += 1
else:
startFound = True
endFound = False
m = len(arr) - 1
while endFound == False:
if arr[m][0] == arr[m-1][0]:
m -= 1
else:
endFound = True
for i in range(n+1, m):
if arr[i][0] == arr[i-1][0]:
None
elif arr[i][0] >= arr[i-1][0] and arr[i][0] >= arr[i+1][0]:
pos = sum([len(arr[idx]) for idx in range(i)])
posPeaks["pos"].append(pos) #.append(i)
posPeaks["peaks"].append(arr[i][0])
return posPeaks
print(peaks(process_data([0, 1, 2, 5, 1, 0])))
print(peaks(process_data([1, 2, 2, 2, 1])))
print(peaks(process_data([1, 2, 2, 2, 3])))
Output:
{'pos': [3], 'peaks': [5]}
{'pos': [1], 'peaks': [2]}
{'pos': [], 'peaks': []}
Here is a fairly simple generator function. Just loop and maintain the necessary state: i (last index of of "growth"), up (true if last value change was "growth")
def peaks(ar):
i, up = 0, False
for j in range(1, len(ar)):
prev, val = ar[j-1], ar[j]
if up and val < prev:
yield prev, i
up = False
if val > prev:
i, up = j, True
>>> list(peaks([0,1,2,5,1,0]))
[(5, 3)]
>>> list(peaks([0,1,2,5,1,2,0]))
[(5, 3), (2, 5)]
>>> list(peaks([0,1,2,5,1,2,0,3]))
[(5, 3), (2, 5)]
>>> list(peaks([1,2,2,2,1]))
[(2, 1)]
>>> list(peaks([1,2,2,2,3]))
[]
A shorter script could be:
data_array = [1, 2, 5, 4, 6, 9]
# Delete the first and the last element of the data array.
reduced_array = [ data_array[i] for i in range(1, len(data_array)-1) ]
# Find the maximum value of the modified array
peak_value = max(reduced_array)
# Print out the maximum value and its index in the data array.
print 'The peak value is: ' + str(peak_value)
print 'And its position is: ' + str(data_array.index(peak_value))
Output:
The peak value is: 6
And its position is: 4

In Python, construct cyclic subgroup from generator

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.

Categories