Related
I have this little code that appends the sum of first n numbers, after that the sum of first n-1 numbers, the sum of first n-2 numbers and so on.
The way I made it may not be the simplest but it just works for me
a = [1,2,3,4,5,6,7,8,9,10]
i = 1
b = []
while i < 11:
b.append(sum(a))
a.pop()
if len(a) == 1:
print(b)
break
This is of course the output:
b = [55,45,36,28,21,15,10,6,3]
Now, I want to create some new lists based on the values of b, in this way:
b[0] + 10
b[1] + 9
b[2] + 8
b[3] + 7
b[4] + 6
b[5] + 5
b[6] + 4
b[7] + 3
b[8] + 2
But I have no idea of making this. Please give me some suggestions. Bye!
Andrea
EDIT
Thanks to all for the support. The simplest way of making what I need I think was
c = [x+10-i for i,x in enumerate(b)]
print(c)
but there is a way to iterate this process starting from the c variable and so on?
EDIT 2
I think I resolved, of course using your help. I wrote:
a = list(range(1,11)
i = 0
b = []
while i < 11
b.append((sum(a))
a.pop()
if len(a) == 1
print(b)
break
numbers = [None] * 10
numbers[i] = [x+10-i for i,x in enumerate(b)]
print(numbers[0])
for i in range(1,9):
numbers[i] = [x+10-i for i,x in enumerate(numbers[i-1])
print(numbers[i])
Of course it is something like spaghetti but it works. Every suggestion about more clear solutions are welcomed!
Bye, Andrea
I would use list(reversed(b)) to get b reversed then iterate though the reversed list and add i to get a
You could enumerate over the results, adding 10 and subtracting the index you're on:
>>> c = [x+10-i for i,x in enumerate(b)]
>>> c
[65, 54, 44, 35, 27, 20, 14, 9, 5]
this could also easly achievable between the zip function:
>>> c = [x+y for x,y in zip(b,range(10,2,-1))]
this list comprehension is equivalent as the following for loop:
>>> c = []
>>> for x,y in zip(b,range(10,2,-1)):
... c.append(x + y)
>>> c
[65, 54, 44, 35, 27, 20, 14, 9, 5]
Your solution works but does not make use of Python's facilities for iteration. Also, you don't need to keep track of the sum, you can rely on the fact that the sum of elements from i to n is actually equal to (n * (n+1) / 2).
For example,
a = list(range(1, 11))
def gauss_trick(l):
out = []
for i in l:
out.append((i * (i + 1)) // 2)
return out
will return [1, 3, 6, 10, 15, 21, 28, 36, 45, 55], you can see the reverse with:
b = gauss_trick(a)
print(b[::-1]) # list reversal
print(b[1:][::-1]) # list reversal after skipping the first element
Then you can add a value based on the index during iteration, it's easily accessed with enumerate, the commented out version will store the output in another list rather than modifying the list in place, if you so desire.
def idx_sum(l):
# out = []
for idx, el in enumerate(l): # gets you index, val for each elem
# out.append(el + idx + 1)
l[idx] = el + idx + 1
Which outputs:
[2, 5, 9, 14, 20, 27, 35, 44, 54, 65]
# You can always ignore the first value with out[1:]
# You can always reverse with out[::-1]
Using the [::-1] also has the advantage of not modifying the list, which means you can use both the reversed and original version of the list only based on how you slice it.
This is the code given below.
k = [1, 8, 15]
g = (x for x in k if k.count(x) > 0)
k = [2, 8, 22]
print(list(g))
I am getting the output as [8] but it should be [1,8,15], right? since each element is present at least once.
Any plausible explanation for the answer?
That's a generator expression. It creates a generator, not a tuple.
Exactly one part of a generator expression is evaluated at genexp creation time. It's this part:
g = (x for x in k if k.count(x)>0)
# ^
Everything else, including this part:
g = (x for x in k if k.count(x)>0)
# ^
is evaluated lazily.
That means the k you're looping over is the original k, but the k you're calling count on is the new k.
Here's a trick to see which k uses the original/modified list by printing x and k in the generator expression:
1st k refers to the original list:
>>> k = [1,8,15]
>>> g = (x for x in k if (print(x) == None and k.count(x)>0))
>>> k = [2,8,22]
>>> list(g)
1
8
15
2nd k refers to the modified list:
>>> k = [1,8,15]
>>> g = (x for x in k if (print(k) == None and k.count(x)>0))
>>> k = [2,8,22]
>>> list(g)
[2, 8, 22]
[2, 8, 22]
[2, 8, 22]
Debugging trick similar to Shawn's:
def p(label, x):
print(label, x)
return x
k = [1,8,15]
g = (x for x in p('iterate over', k) if p('count in', k).count(x)>0)
k = [2,8,22]
print('between generator construction and consumption')
list(g)
Output (Try it online!):
iterate over [1, 8, 15]
between generator construction and consumption
count in [2, 8, 22]
count in [2, 8, 22]
count in [2, 8, 22]
Generator is fetch on process memory,work like lazy operator so that happen
"""""for x in [1,8,15]:
if [2,8,22].count(x): """"
That is how interpreter fetch values.
Refer this tweet for more understand:
https://twitter.com/nedbat/status/1503735148378001410?t=lJLT482Vmt19cBNuP-PAWQ&s=19
https://twitter.com/driscollis/status/1503366898234404866?t=OgCM0E1rzWAEQOOziO9uqA&s=19
#Learning with hope
Given a list of numbers and a number k, return whether any two numbers from the list add up to k.
For example, given [10, 15, 3, 7] and k of 17, return true since 10 + 7 is 17.
n=0,
Axe= [10, 15, 3, 7],
uplimit=len(Axe)
for x in range(uplimit):
print(Axe[n])
print(Axe[x:uplimit])
print (Axe[n]+ Axe[x])
i am stuck here. i can get the fist value to be added with the rest, but dont know how to get the rest to do the same.
I can do it manually of course but i need to automate the process
This function should do the trick
def my_function(mylist, k):
for i in range(len(mylist)):
first = mylist[i]
for second in mylist[i:]:
print(f"{first} + {second} = {first+second}")
if first+second ==k:
return True
return False
You can also use itertools:
import itertools
def sum_pairs(num_list, k):
all_pairs = list(itertools.combinations(num_list, 2))
for pair in all_pairs:
if sum(pair) == k:
return True
return False
You can then call the above function:
Axe = [10, 15, 3, 7]
k = 17
print(sum_pairs(Axe, k))
list = [10, 15, 3, 7]
k = 17
for i in range(len(list)):
temp = list[i]
for i in range(len(list)):
if (temp + list[i] == k ):
print("true")
return
I'm currently working on an api where they send me a str range in this format: "1-5,10-25,27-30" and i need add or remove number conserving the format.
if they send me "1-5,10-25,27-30" and I remove "15" the result must be "1-5,10-14,16-25,27-30" and if they send me "1-5,10-25,27-30" and i add "26" the result must be "1-5,10-30"
i've been trying converting the entire range into a list of numbers, delete the target and converting it again but it's very slow doing in this way becuase they send 8-digits numbers so iter then it's not the best way
how can i do this? is a library for work with this format?
thanks!
intspan deals with ranges of integers and operations on them
>>> from intspan import intspan
>>> s = "1-5,10-25,27-30"
>>> span = intspan(s)
>>> str(span)
'1-5,10-25,27-30'
>>> span.add(26)
>>> str(span)
'1-5,10-30'
>>> span.discard(15)
>>> str(span)
'1-5,10-14,16-30'
This represents ranges by lists of two-element lists. Two-element lists are used as this allows ranges boundaries to be mutated.
# -*- coding: utf-8 -*-
"""
https://stackoverflow.com/questions/64466231/pythonic-way-to-operate-comma-separated-list-of-ranges-1-5-10-25-27-30
Created on Wed Oct 21 16:29:39 2020
#author: Paddy3118
"""
def to_ranges(txt):
return [[int(x) for x in r.strip().split('-')]
for r in txt.strip().split(',')]
def remove_int(rem, ranges):
for i, r in enumerate(ranges):
if r[0] <= rem <= r[1]:
if r[0] == rem: # range min
if r[1] > rem:
r[0] += 1
else:
del ranges[i]
elif r[1] == rem: # range max
if r[0] < rem:
r[1] -= 1
else:
del ranges[i]
else: # inside, range extremes.
r[1], splitrange = rem - 1, [rem + 1, r[1]]
ranges.insert(i + 1, splitrange)
break
if r[0] > rem: # Not in sorted list
break
return ranges
def add_int(add, ranges):
for i, r in enumerate(ranges):
if r[0] <= add <= r[1]: # already included
break
elif r[0] - 1 == add: # rough extend to here
r[0] = add
break
elif r[1] + 1 == add: # rough extend to here
r[1] = add
break
elif r[0] > add: # rough insert here
ranges.insert(i, [add, add])
break
else:
ranges.append([add, add])
return ranges
return consolidate(ranges)
def consolidate(ranges):
"Combine overlapping ranges"
for this, that in zip(ranges, ranges[1:]):
if this[1] + 1 >= that[0]: # Ranges interract
if this[1] >= that[1]: # this covers that
this[:], that[:] = [], this
else: # that extends this
this[:], that[:] = [], [this[0], that[1]]
ranges[:] = [r for r in ranges if r]
return ranges
sent = "1-5,10-25,27-30"
ll = to_ranges(sent)
assert ll == sorted(ll)
Sample calculations
In [68]: ll
Out[68]: [[1, 5], [10, 25], [27, 30]]
In [69]: add_int(26, ll)
Out[69]: [[1, 5], [10, 30]]
In [70]: add_int(9, ll)
Out[70]: [[1, 5], [9, 30]]
In [71]: add_int(7, ll)
Out[71]: [[1, 5], [7, 7], [9, 30]]
In [72]: remove_int(26, ll)
Out[72]: [[1, 5], [7, 7], [9, 25], [27, 30]]
In [73]: remove_int(9, ll)
Out[73]: [[1, 5], [7, 7], [10, 25], [27, 30]]
In [74]: remove_int(7, ll)
Out[74]: [[1, 5], [10, 25], [27, 30]]
In [75]:
You could use a variation of the sweep line algorithm. Convert your string to a list of tuples [(1,5),(10,25),(27,30)], stepping through the tuples to see if your number is in there. If it is, split the tuple like so: [(1,5),(10,14),(16,25),(27,30)]. Otherwise, do nothing.
Like what #Jace is saying, here is a possible implementation assuming non-overlapping ranges:
# delete a number
rngs = [(10, 25), (1, 5), (27, 30)]
rngs.sort() # you can even sort them (sorted by first number)
print(rngs)
delete = 15
for i, r in enumerate(rngs):
if r[0] <= delete <= r[-1]:
if delete == r[0]:
rngs[i] = (r[0] + 1, r[1])
elif delete == r[1]:
rngs[i] = (r[0], r[1] - 1)
else:
rngs[i] = (r[0], delete - 1)
rngs.insert(i + 1, (delete + 1, r[1]))
# done
break
print(rngs)
# add a number
rngs = [(1, 5), (10, 25), (27, 30)]
number = 26
added = False
for i, r in enumerate(rngs):
if r[0] - 1 == number: # is the previous number of the range
rngs[i] = (number, r[1])
added = True
break
elif r[1] + 1 == number: # is the next number of the range
# check if next range should also be mixed
if i < len(rngs) - 1 and rngs[i + 1][0] - 1 == number:
lhs, rhs = rngs[i + 1]
rngs[i] = (r[0], rhs)
rngs.remove((lhs, rhs))
else:
rngs[i] = (r[0], number)
added = True
break
if not added:
rngs.append((number, number))
rngs.sort()
print(rngs)
This works perfectly for removing values from the string, and has no huge performance losses with large numbers:
input_ = '1-5,10-25,27-30'
ranges = input_.split(',')
ranges = [range(int(val.split('-')[0]), int(val.split('-')[1])) for val in ranges]
def remove_value(value, ranges):
new_ranges = []
for range_obj in ranges:
if value in range_obj:
new_ranges.append(range(range_obj.start, value-1))
new_ranges.append(range(value+1, range_obj.end))
else:
new_ranges.append(range_obj)
return new_ranges
ranges = remove_value(20, ranges)
output = ','.join(f'{r.start}-{r.stop}' for r in ranges)
In the following code I want to add second parameters of list=[(0,3),(2,6),(1,10)] in a for loop. first iteration should be 3+6=9 and the second iteration should add output of previous iteration which is 9 to 10---> 9+10=19 and I want final output S=[9,19]. I am not sure how to do it, Should I add another loop to my code?
T=[(0,3),(2,6),(1,10)]
S=[]
for i in range(len(T)):
b=T[0][i]+T[0][i+1]
S.append(b)
use itertools.accumulate
spam = [(0,3),(2,6),(1,10)]
from itertools import accumulate
print(list(accumulate(item[-1] for item in spam))[1:])
output
[9, 19]
Use zip to combine the vales from the tuples, with the same index.
Use an assignment expression (from python 3.8), in a list-comprehension, to sum the values in the second tuple, T[1], of T.
T = [(0,3),(2,6),(1,10)]
T = list(zip(*T))
print(T)
[out]:
[(0, 2, 1), (3, 6, 10)]
# use an assignment expression to sum T[1]
total = T[1][0] # 3
S = [total := total + v for v in T[1][1:]]
print(S)
[out]:
[9, 19]
Just modify your code as below
T=[(0,3),(2,6),(1,10)]
S=[]
b = T[0][1]
for i in range(1,len(T)):
b+=T[i][1]
S.append(b)
This should help u:
T=[(0,3),(2,6),(1,10)]
lst = [T[i][1] for i in range(len(T))]
final_lst = []
for x in range(2,len(lst)+1):
final_lst.append(sum(lst[:x]))
print(final_lst)
Output:
[9, 19]
If u prefer list comprehension, then use this line instead of the last for loop:
[final_lst.append(sum(lst[:x])) for x in range(2,len(lst)+1)]
Output:
[9, 19]
Here is a solution with native recursion
import operator
mylist =[(0,3),(2,6),(1,10)]
def accumulate(L, i, op):
def iter(result, rest, out):
if rest == []:
return out
else:
r = op(result, rest[0][i-1])
return iter(r, rest[1:], out + [r])
return iter(L[0][i-1], L[1:], [])
print(accumulate(mylist, 2, operator.add))
print(accumulate(mylist, 1, operator.add))
print(accumulate(mylist, 2, operator.mul))
# ==>
# [9, 19]
# [2, 3]
# [18, 180]