How can I make my output group all numbers together? - python

So I'm trying to find how to group similar numbers into different lists. I tried looking at some sources like (Grouping / clustering numbers in Python)
but all of them requires the importation of itertools and use itertools.groupby, which I dont want because I dont want to use built in functions.
Here is my code so far.
def n_length_combo(lst, n):
if n == 0:
return [[]]
l = []
for i in range(0, len(lst)):
m = lst[i]
remLst = lst[i + 1:]
for p in n_length_combo(remLst, n - 1):
l.append([m] + p)
return l
print(n_length_combo(lst=[1,1,76,45,45,4,5,99,105],n=3))
Edit: n: int represents the number of groups permitted from one single list, so if n is 3, the numbers will be grouped in (x,...), (x,....) (x,...) If n = 2, the numbers will be grouped in (x,..),(x,...)
However, my code prints out all possible combinations in a list of n elements. But it doesnt group the numbers together. So what I want is: for instance if the input is
[10,12,45,47,91,98,99]
and if n = 2, the output would be
[10,12,45,47] [91,98,99]
and if n = 3, the output would be
[10,12] [45,47] [91,98,99]
What changes to my code should I make?

Assuming n is the number of groups/partitions you want:
import math
def partition(nums, n):
partitions = [[] for _ in range(n)]
min_, max_ = min(nums), max(nums)
r = max_ - min_ # range of the numbers
s = math.ceil(r / n) # size of each bucket/partition
for num in nums:
p = (num - min_) // s
partitions[p].append(num)
return partitions
nums = [10,12,45,47,91,98,99]
print(partition(nums, 2))
print(partition(nums, 3))
prints:
[[10, 12, 45, 47], [91, 98, 99]]
[[10, 12], [45, 47], [91, 98, 99]]

You are trying to convert a 1d array into a 2d array. Forgive the badly named variables but the general idea is as follows. It is fairly easy to parse, but basically what we are doing is first finding out the size in rows of the 2d matrix given the length of the 1d matrix and desired number of cols. If this does not divide cleanly, we add one to rows. then we create one loop for counting the cols and inside that we create another loop for counting the rows. we map the current position (r,c) of the 2d array to an index into the 1d array. if there is an array index out of bounds, we put 0 (or None or -1 or just do nothing at all), otherwise we copy the value from the 1d array to the 2d array. Well, actually we create a 1d array inside the cols loop which we append to the lst2 array when the loop is finished.
def transform2d(lst, cols):
size = len(lst)
rows = int(size/cols)
if cols * rows < size:
rows+=1
lst2 = []
for c in range(cols):
a2 = []
for r in range(rows):
i = c*cols + r
if i < size:
a2.append(lst[i])
else:
a2.append(0) # default value
lst2.append(a2)
return lst2
i = [10,12,45,47,91,98,99]
r = transform2d(i, 2)
print(r)
r = transform2d(i, 3)
print(r)
the output is as you have specified except for printing 0 for the extra elements in the 2d array. this can be changed by just removing the else that does this.

Related

Sum by Factors From Codewars.com

Sinopsis: my code runs well with simple lists, but when I attempt, after the 4 basic test its execution time gets timed out.
Since I don't want to look for others solution, I'm asking for help and someone can show me which part of the code its messing with the time execution in order to focus only into modify that part.
Note: I don't want a finally solution, just know which part of the code I have to change please
Exercise:
Given an array of positive or negative integers
I= [i1,..,in]
you have to produce a sorted array P of the form
[ [p, sum of all ij of I for which p is a prime factor (p positive) of ij] ...]
P will be sorted by increasing order of the prime numbers. The final result has to be given as a string in Java, C# or C++ and as an array of arrays in other languages.
Example:
I = [12, 15] # result = [[2, 12], [3, 27], [5, 15]]
[2, 3, 5] is the list of all prime factors of the elements of I, hence the result.
Notes: It can happen that a sum is 0 if some numbers are negative!
Example: I = [15, 30, -45] 5 divides 15, 30 and (-45) so 5 appears in the result, the sum of the numbers for which 5 is a factor is 0 so we have [5, 0] in the result amongst others.
`
def sum_for_list(lst):
if len(lst) == 0:
return []
max = sorted(list(map(lambda x: abs(x), lst)), reverse = True)[0]
#create the list with the primes, already filtered
primes = []
for i in range (2, max + 1):
for j in range (2, i):
if i % j == 0:
break
else:
for x in lst:
if x % i == 0:
primes.append([i])
break
#i add the sums to the primes
for i in primes:
sum = 0
for j in lst:
if j % i[0] == 0:
sum += j
i.append(sum)
return primes
`
Image
I tried to simplyfy the code as much as I could but same result.
I also tried other ways to iterate in the first step:
# Find the maximum value in the list
from functools import reduce
max = reduce(lambda x,y: abs(x) if abs(x)>abs(y) else abs(y), lst)

How to get a symmetrical sub list and then get the sum of that sub list?

What the code does: Takes a Python list of integers as input and searches for a 'symmetrical' inner-portion of the list then it takes that inner portion and gets the sum of it.
Symmetry occurs if the value of the ith element from the start of the list is equal to the value of the ith element from the end of the list.
Examples of what i want:
symmetrical_sum([10,11,12,11,12]) == ([11, 12, 11], 34)
symmetrical_sum([9,99,88,8,77,7,77,8,88,10,100]) == ([88, 8, 77, 7, 77, 8, 88], 353)
symmetrical_sum([10,8,7,5,9,8,15]) == ([8, 7, 5, 9, 8], 37)
Is there any short-coded solution to get the outputs in the examples given above? I have a correct coded version but it is more than 30 lines of code and would like to know if there is shorter way.
def symmetrical_sum(a):
dup=[x for n, x in enumerate(a) if x in a[:n]] #to get the duplicate
to_int = int(''.join(map(str,dup))) #change duplicate into int
dup1_index=a.index(to_int) #index the first duplicate
dup2_index=a.index(to_int,dup1_index+1) #index the second duplicate
portion=a[dup1_index:dup2_index+1] #get the symetric portion
total = sum(portion) #sum the elements in portion
tuple1 = (portion,total) #create tuple
return tuple1
You can do this with a recursive function as follows:
def sym(L):
if L[0] == L[-1]:
lis, sum_list = L, sum(L)
answer = f'inner-portion: {lis}, sum: {sum_list}'
return answer
else:
return sym(L[1:-1])
Note that the above will work for a list input with odd number items (that is the length is an odd number)and a single item list but not an empty list. A more wholistic approach is the following:
def symmetrical_sum(a):
index_from_start = 0
index_from_end= len(a)-1
sym_list= []
while index_from_start<=index_from_end:
if a[index_from_start] == a[index_from_end]:
sym_list= a[index_from_start:index_from_end+1]
break
else:
index_from_start += 1
index_from_end -= 1
return sym_list, sum(sym_list)
QED :)
Try using numpy:
get a list of booleans representing the condition if ith element from beginning and end are equal
find indices where the boolean values are True
The min value represent where symmetry starts and max value is where it ends, so slice the list array to get the "symmetrical" sub-list
return the new list and its sum as a tuple
Following code should work for the input and output you posted:
import numpy as np
def sym_sum(arr):
l = len(arr)-1
bool_arr = np.array([x==arr[l-i] for i,x in enumerate(arr)])
idx_arr = np.where(bool_arr==True)[0]
if len(idx_arr):
res = arr[min(idx_arr):max(idx_arr)+1]
else:
res = []
return (res, sum(res))
If you need actual symmetrical output use:
import numpy as np
def get_sym(arr):
l = len(arr) - 1
bool_arr = np.array([x == arr[l - i] for i, x in enumerate(arr)])
idx_arr = np.where(bool_arr == False)[0]
if len(idx_arr):
return get_sym(arr[min(idx_arr)+1:max(idx_arr)])
else:
return (arr, sum(arr))
Here we recursively call the function until the unsymmetrical portions are completely striped.
In pure python this can be achieved like this:
def symmetrical_sum(a):
inner_portion = []
sum = 0;
start = 0;
for i in a:
end = len(a) - (start + 1);
if a[start] == a[end]:
inner_portion = a[start:(end+1)];
for i in inner_portion:
sum+= i
break
start+= 1
return (inner_portion, sum)
print(symmetrical_sum([10,11,12,11,12])) #([11, 12, 11], 34)
Mid = float(len(a))/2
my_list =a[int(Mid - .5): int(Mid + .5)]
my_list_total =sum(my_list)
get_total= (my_list,my_list_total)
answer return get_total ([5], 5)

Finding the subarray with the minimum range

Given an array of N positive integers, ranging from index 0 to N - 1, how can I find a contiguous subarray of length K with the minimum range possible. In other words, max(subarray) - min(subarray) is minimised. If there are multiple answers, any is fine.
For example, find the subarray of length 2 with the smallest range from [4, 1, 2, 6]
The answer would be [1, 2] as 2 - 1 = 1 gives the smallest range of all possible contiguous subarrays.
Other subarrays are [4, 1] (range 3), [2, 6] (range 4)
I'm using python and so far I've tried a linear search with min() max() functions and it just doesn't seem efficient to do so. I've thought of using a minheap but I'm not sure how you would implement this and I'm not even sure if it would work. Any help would be much appreciated.
edit: code added
# N = length of array_of_heights, K = subarray length
N, K = map(int, input().split(' '))
array_of_heights = [int(i) for i in input().split(' ')]
min_min = 100000000000000000000
# iterates through all subarrays in the array_of_heights of length K
for i in range(N + 1 - K):
subarray = land[i : i + K]
min_min = min(max(subarray)-min(subarray), min_min)
print(min_min)
There is linear-time algorithm O(N)for getting min or max in moving window of specified size (while your implementation has O(N*K) complexity)
Using deque from collections module you can implement two parallel deques keeping minumum and maximum for current window position and retrieve the best difference after the only walk through the list.
import collections
def mindiff(a, k):
dqmin = collections.deque()
dqmax = collections.deque()
best = 100000000
for i in range(len(a)):
if len(dqmin) > 0 and dqmin[0] <= i - k:
dqmin.popleft()
while len(dqmin) > 0 and a[dqmin[-1]] > a[i]:
dqmin.pop()
dqmin.append(i)
if len(dqmax) > 0 and dqmax[0] <= i - k:
dqmax.popleft()
while len(dqmax) > 0 and a[dqmax[-1]] < a[i]:
dqmax.pop()
dqmax.append(i)
if i >= k - 1:
best = min(best, a[dqmax[0]]-a[dqmin[0]])
return best
print(mindiff([4, 1, 2, 6], 2))
You could use numpy to improve execution time.
Example:
def f1(l,k):
subs = np.array([l[i:i+k] for i in range(len(l)-k+1)])
return np.min(subs.max(axis=1) - subs.min(axis=1))
Small test (f2 is your function here).
>>> arr = np.random.randint(100,size=10000)
>>> timeit.timeit("f1(arr,4)",setup="from __main__ import f1,f2,np,arr",number=1)
0.01172515214420855
>>> timeit.timeit("f2(arr,4)",setup="from __main__ import f1,f2,np,arr",number=1)
14.226237731054425

How to generate and filter efficiently all combinations of a list of list product

Hello guys here is the problem. I have something like this in input [[1,2,3],[4,5,6],[7,8,9]]...etc
And i want to generate all possible combination of product of those list and then multiply each elements of the resulting combination beetween them to finally filter the result in a interval.
So first input a n list [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]...etc
Which will then give (1,4,7,10)
(1,4,7,11)
(1,4,7,12)
and so on
Then combination of those result for k in n like (1,4,7)(1,4,10)(1,7,10) for the first row
The multiplication of x as 1*4*7 = 28, 1*4*10 = 40, 1*7*10 = 70
And from this get only the unique combination and the result need in the interval choosed beforehand : if x > 50 and x < 100 i will get (1,7,10) : 70
I did try
def mult(lst): #A function mult i'm using later
r = 1
for element in lst:
r *= element
return round(r)
s = [] #Where i add my list of list
for i in range(int(input1)):
b = input("This is line %s : " % (i+1)).split()
for i in range(len(b)):
b[i] = float(b[i])
s.append(b)
low_result = input("Expected low_result : ")
high_result = input("Expected high_result : ")
combine = []
my_list = []
for element in itertools.product(*s):
l= [float(x) for x in element]
comb = itertools.combinations([*l], int(input2))
for i in list(comb):
combine.append(i)
res = mult(i)
if res >= int(low_result) and res <= int(high_result):
my_list.append(res)
f = open("list_result.txt","a+")
f.write("%s : result is %s\n" % (i, res))
f.close()
And it always result in memory error cause there is too many variation with what i'm seeking.
What i would like is a way to generate from a list of list of 20 elements or more all the product and resulting combination of k in n for the result(interval) that i need.
As suggested above, I think this can be done without exploding your memory by never holding an array in memory at any time. But the main issue is then runtime.
The maths
As written we are:
Producing every combination of m rows of n items n ** m
Then taking a choice of c items from those m values C(m, c)
This is very large. If we have m=25 rows, of n=3 items each and pick c=3 items in them we get:
= n ** m * C(m, c)
= 3 ** 25 * 2300 - n Choose r calculator
= 1.948763802×10¹⁵
If instead we:
Choose c rows from the m rows: C(m, c) as before
Then pick every combination of n items from these c rows: n ** c
With m=25 rows, of n=3 items each and pick c=3 items in them we get:
= n ** c * C(m, c)
= 3 ** 3 * 2300
= 20700
This is now a solvable problem.
The code
from itertools import product, combinations
def mult(values, min_value, max_value):
"""
Multiply together the values, but return None if we get too big or too
small
"""
output = 1
for value in values:
output *= value
# Early return if we go too big
if output > max_value:
return None
# Early return if we goto zero (from which we never return)
if output == 0 and min_value != 0:
return None
if output < min_value:
return None
return output
def yield_valid_combos(values, choose, min_value, max_value):
# No doubt an even fancier list compression would get this too
for rows in combinations(values, choose):
for combos in product(*rows):
value = mult(combos, min_value, max_value)
if value is not None:
yield combos, value
values = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
with open('list_result.txt', 'w') as fh:
for selection, value in yield_valid_combos(
values, choose=3, min_value=50, max_value=100):
fh.write('{}: result is {}\n'.format(selection, value))
This solution also returns no duplicate answers (unless the same value appears in multiple rows).
As an optimisation the multiplication method attempts to return early if we detect the result will be too big or small. We also only open the file once and then keep adding rows to it as they come.
Further optimisation
You can also optimise your set of values ahead of time by screening out values which cannot contribute to a solution. But for smaller values of c, you may find this is not even necessary.
The smallest possible combination of values is c items from the set of the smallest values in each row. If we take the c - 1 smallest items from the set of smallest values, mutliply them together and then divide the maximum by this number, it gives us an upper bound for the largest value which can be in a solution. We can then then screen out all values above this value (cutting down on permutations)

I want to create array problem using python

You all have seen how to write loops in python. Now is the time to implement what you have learned.
Given an array A of N numbers, you have to write a program which prints the sum of the elements of array A with the corresponding elements of the reverse of array A.
If array A has elements [1,2,3], then reverse of the array A will be [3,2,1] and the resultant array should be [4,4,4].
Input Format:
The first line of the input contains a number N representing the number of elements in array A.
The second line of the input contains N numbers separated by a space. (after the last elements, there is no space)
Output Format:
Print the resultant array elements separated by a space. (no space after the last element)
Example:
Input:
4
2 5 3 1
Output:
3883
Explanation:
Here array A is [2,5,3,1] os reverse of this array is [1,3,5,2] and hence the resultant array is [3,8,8,3]
My solution is not working.
my solution is:
r=input()
r=int(r)
result_t = []
d=[]
for i in range(0, r):
c=input()
c=int(c)
t = i
result_t.append(c)
d=reversed(result_t)
d=int(d)
s=result_t+d
for i in range(0, r):
print(s[i])
You just need to loop over both result_t and d. You can use zip() to combine two lists so you can loop over them in parallel:
r=input()
r=int(r)
result_t = []
for i in range(r):
c=input()
c=int(c)
result_t.append(c)
d = reversed(result_t)
result = [x + y for x, y in zip(result_t, d)]
print(result.join(" "))
You can also do it without making the reversed list.
result = [x + result_t[-(i+1)] for i, x in enumerate(result_t)]
When you use a negative index in a list, it counts from the end. You have to add 1 before negating, because the last element is -1 (since -0 is the same as 0, which is the first element).
"can only concatenate list (not "list_reverseiterator") to list"
reversed(result_t) returns not the list but iterator
try:
rev = []
for i in reversed(result_t):
rev.append(i)
print(rev)
Try This One:
x = input()
result_t = [int(x) for x in input().split()]
rev = [x for x in reversed(result_t)]
result = [int(x) + int(y) for x, y in zip(result_t, rev)]
for i in result:
print(i,end=" ")
Here array A is [2,5,3,1] and reverse of this array is [1,3,5,2] and hence the resultant array is [3,8,8,3].
a = []
n = int(input("Enter the number of elements"))
for i in range(n):
x = int(input("Enter the elements"))
a.append(x)
print(a)
res = []
b = [None] * len(a)
for i in range(0, len(a)):
b[i] = a[i]
b.reverse()
print(b)
for i in range(0, len(a)):
res.append(a[i] + b[i])
print(res)

Categories