add neigbouring elements in a list - python

How can I write a function which takes a list of integers and creates a new list with the same number of elements as the original list such that each integer in the new list is the sum of its neighbours and itself in the original list. For example, if a_list = [10, 20, 30, 40, 50], the new_list = [30, 60, 90, 120, 90].
I tried a list comprehension;
def sum_neighbours(a_list):
b_list = a_list
li = [x+y for x in a_list for y in b_list]
return li
print(sum_neighbours([10, 20, 30, 40, 50]))
Which gave me;
[20, 30, 40, 50, 60, 30, 40, 50, 60, 70, 40, 50,
60, 70, 80, 50, 60, 70, 80, 90, 60, 70, 80, 90, 100]
I then tried a for loop;
def sum_neighbours(a_list):
element1 = a_list[0]
new_list = []
for element in a_list:
element1 += element
new_list += element1
return new_list
print(sum_neighbours([10,20,30,40,50]))
Which threw a TypeError: 'int' object is not iterable
But in both cases I don't think my ideas/attempts are on the right track... I would really appreciate any help, hints, tips that more experienced people may have.

You can start with a solution that iterates through the indexes of the list, like so:
def sum_neighbours1(a_list):
result = []
for i in range(len(a_list)):
if i == 0:
result.append(a_list[i] + a_list[i+1])
elif i == len(a_list)-1:
result.append(a_list[i-1] + a_list[i])
else:
result.append(a_list[i-1] + a_list[i] + a_list[i+1])
return result
print(sum_neighbours1([10,20,30,40,50]))
Or, you can build three distinct lists: the original list, the list of left-hand neighbors, and the list of right-hand neighbors. We have to put 0 at the front or rear of the auxiliary lists. Each of the lists must be at least as long as the original list.
Zip the three lists together, and add them:
def sum_neighbours2(a_list):
priors = [0] + a_list
subsequents = a_list[1:] + [0]
return map(sum, zip(priors, a_list, subsequents))
Note that I used the functional notation map(sum, data), but I could have used a list conprehension just as easily:
def sum_neighbours3(a_list):
priors = [0] + a_list
subsequents = a_list[1:] + [0]
return [p+a+s for p,a,s in zip(priors, a_list, subsequents)]
And, if I were eager to make the result a single expression (for example, if it had to fit in a lambda expression), here that is:
def sum_neighbours4(a_list):
return [
left + a + right
for left, a, right in zip(
[0] + a_list,
a_list,
a_list[1:] + [0])
]

Here is my one line solution with zip :
def sum_neighbours(a) :
return [sum(x) for x in [(a[0],a[1])]+zip(a,a[1:],a[2:])+[(a[-2],a[-1])]]
print sum_neighbours([10, 20, 30, 40, 50]) # display [30, 60, 90, 120, 90]
with :
a, the original list
zip(a,a[1:],a[2:]), 3-tuples generation
[(a[0],a[1])] and [(a[-2],a[-1])], 2-tuples for particular cases (first and last numbers of list)

You'll probably want a for i in range loop, and indexing directly into the array so you can look at the element that is at i+1 and i-1 indexes (making sure to check that your +/- 1 isn't going outside the bounds of the array).

Related

My list comparator doesn't want to run the way I want it to

I'm a beginer in python and I have a task where the winner_round function compares two lists and count how many rounds there were in the game in which Adam's team scored more points than the opponent. If the two list don't match then return with -1
This is my code:
def winner_round(list1,list2):
list1 = [30, 50, 10, 80, 100, 40]
list2 = [60, 20, 10, 20, 30, 20]
point = 0
for i in winner_round(list1,list2):
if list1>list2:
return -1
print(-1)
for pointA in list1:
for pointE in list2:
if pointA > pointE:
point+=1
break
return(point)
print(point)
Sorry for my english
The only reason to return -1 is if the lists have different sizes; you can check that with len, an O(1) operation, before you bother iterating.
After that, it's just a matter of point-wise comparisons of list items. Assuming list1 is Adam and list2 his opponent,
def winner_round(list1, list2):
if len(list1) != len(list2):
return -1
return sum(x > y for x, y in zip(list1, list2))
zip(list1, list2) produces the pairs (30, 60), (50, 20), etc. Because True == 1 and False == 0 (bool being a subclass of int), you can simply sum the results where the value from list1 is the greater value of a pair.
(You can also use map, since a 2-argument function as the first argument allows you to pass the two lists as the 2nd and 3rd arguments, replacing the need for more explicit iteration over the zip instance. operator.gt provides the function you need:
return sum(map(operator.lt, list1, list2))
Which one is "better" is a matter of personal preference.)
Compare each item one by one if it's greater than the other then add 1 to point
list1 = [30, 50, 10, 80, 100, 40]
list2 = [60, 20, 10, 20, 30, 20]
def winner_round(list1,list2):
point = 0
if len(list1)!=len(list2):
return -1
for i in range(len(list1)):
if list1[i] > list2[i]:
point+=1
return point
sum of points:
list1 = [30, 50, 10, 80, 100, 40]
list2 = [60, 20, 10, 20, 30, 20]
def winner_round(list1,list2):
if sum(list1) > sum(list2):
return 1
else:
return 2
comparing each round:
list1 = [30, 50, 10, 80, 100, 40]
list2 = [60, 20, 10, 20, 30, 20]
def winner_round(list1,list2):
if len(list1) != len(list2): return -1
score1, score2 = 0
for i in range(list1):
if list1[i] > list2[i]:
score1 +=1
else:
score2 +=1
if score1 > score2:
return 1
else:
return 2
This would be my solution to your problem:
def get_points(teamA,teamB):
if len(teamA)!=len(teamB):
print("Both lists have to be of same length.")
return -1
points=0
for i in range(len(teamA)):
if teamA[i]>teamB[i]:
points+=1
print("points:",points)
return points
I first checked, whether both of the lists have the same length and then looped through both of the lists and increased a counter if one is bigger than the other one.(Btw you tried to print something after the return statement, which exists the function)
Hope it helps, Lars

Python list of objects vs list of primitives

Following is the MWE:
class Foo():
def __init__(self, data):
self.data = data
def __repr__(self):
return str(self.data)
object_list = [Foo(10), Foo(80), Foo(50), Foo(60), Foo(20)]
int_list = [10, 80, 50, 60, 20]
print("Object list before modification: {}".format(object_list))
print("Integer list before modification: {}".format(int_list))
for i in object_list:
i.data += 5
for j in int_list:
j += 5
print("")
print("Object list after modification: {}".format(object_list))
print("Integer list after modification: {}".format(int_list))
The output is as follows:
Object list before modification: [10, 80, 50, 60, 20]
Integer list before modification: [10, 80, 50, 60, 20]
Object list after modification: [15, 85, 55, 65, 25]
Integer list after modification: [10, 80, 50, 60, 20]
Why are the results different? In my opinion, the integer result seems more natural as we are not exactly performing the operation on the list (like for idx in range(len(object_list)): object_list[idx].data += 5). We are rather applying it on the elements after we take them out.
This is the strangeness of augmented assignment. "+=" takes three steps: 1) get the value from the left hand side, 2) add the value on the right hand side 3) store the result back in the variable on the left hand side.
In your first case, the left hand side is i.data and i.data is reassigned to the result. Since the object in i is in the original list, its reassigned attribute "data" shows the change.
In your second case, the left hand side is j. It us updated properly, but since j isn't saved anywhere, its value is lost.

How to remove items from smaller lists that are in a larger list?

Hi I have one big list which consist of 10 smaller list. In each smaller list are 10 random numbers.
Depending on the variable, either even or not even variables must be visible.The example below I made only for 2 smaller lists to make it easier to see the output.
This is my code.
def generate_random_number_list_10(len_of_elements):
my_list=[random.randint(1,100) for x in range (len_of_elements)]
return my_list
def generate_list_consist_of_10_smaller_list(amount_of_list,len_of_elements,variable):
big_list=[generate_random_number_list_10(len_of_elements) for x in range (amount_of_list)]
print (big_list)
if variable%2 == 0:
for num in big_list :
for x in num:
filtered_list = list(filter(lambda x: x%2==0, num))
print (filtered_list)
generate_list_consist_of_10_smaller_list(2,8,8)
This is my output:
[[1, 47, 25, 84, 48, 8, 91, 89], [99, 40, 54, 50, 52, 83, 86, 61]] - for example big list cosist of 2 smaller list
[40, 54, 50, 52, 86] - my solution is correct only for last smaller list
[[ 84, 48, 8], [ 40, 54, 50, 52, 86]] -this is correct solution
For a larger number of smaller lists, my solution filters even numbers only for the last smaller list.
How to apply filtering to all smaller lists, regardless of how many there are?
filtered_list needs to be a list of lists.
Also, you don't need the for x loop, since filter() does that looping automatically.
def generate_list_consist_of_10_smaller_list(amount_of_list,len_of_elements,variable):
big_list=[generate_random_number_list_10(len_of_elements) for x in range (amount_of_list)]
print (big_list)
if variable%2 == 0:
filtered_list = [list(filter(lambda x: x%2==0, num)) for num in big_list]
print (filtered_list)

How to iterate unequal nested lists to create a new list Python

I'm stuck on iterating several nested lists in order to calculate Call options by using a Python module, Mibian.
If I use mibian to calculate made up European call options.
import mibian as mb
mb.BS([stock price, strike price, interest rate, days to maturity], volatility)
my_list = [[20, 25, 30, 35, 40, 45],
[50, 52, 54, 56, 58, 60, 77, 98, 101],
[30, 40, 50, 60]]
For calculating multiple call options, first, I create a range.
If I select, say the first nested list, my_list[0], and run a for-loop. I get all the call options for the stock.
range_list = list(range(len(my_list)))
range_list
# [0, 1, 2]
data = dict()
for x in range_list:
data[x] = option2 = []
for i in my_list[0]:
c = mb.BS([120, i, 1, 20 ], 10)
option2.append(c.callPrice)
option2
This gives the 6 call prices of the first nested list from my_list.
Output:
[100.01095590221843,
95.013694877773034,
90.016433853327641,
85.019172828882233,
80.021911804436854,
75.024650779991447]
What I'm trying to figure out, is how I can iterate all the nested lists in one go, and get a new list of nested lists that contain the call option prices for my_list[0], my_list[1], and my_list[2].
I'd like this output in one go for all three nested lists.
Output:
[[100.01095590221843, [70.027389755546068, [90.016433853327641,
95.013694877773034, 68.028485345767905, 80.021911804436854,
90.016433853327641, 66.029580935989742, 80.021911804436854,
85.019172828882233, 64.030676526211579, 70.027389755546068,
80.021911804436854, 62.03177211643343, ]]
75.024650779991447] 60.032867706655267,
43.042180223540925,
22.05368392087027,
19.055327306203068]
Can anyone help? I'm sure it's something very simple that I'm missing.
Many thanks.
P.S. I can't get the indentation right when editing my code on here.
Let's start with your current approach:
range_list = list(range(len(my_list)))
data = dict()
for x in range_list:
data[x] = option2 = []
for i in my_list[0]:
c = mb.BS([120, i, 1, 20 ], 10)
option2.append(c.callPrice)
The first thing you should note is that there is enumerate to get the index and the part at the same time, so you can omit the range_list variable:
data = dict()
for x, sublist in enumerate(my_list):
data[x] = option2 = []
for i in my_list[0]:
c = mb.BS([120, i, 1, 20 ], 10)
option2.append(c.callPrice)
This also takes care of the problem with the "dynamic indexing" because you can just iterate over the sublist:
data = dict()
for x, sublist in enumerate(my_list):
data[x] = option2 = []
for i in sublist:
c = mb.BS([120, i, 1, 20 ], 10)
option2.append(c.callPrice)
Then you can use a list comprehension to replace the inner loop:
data = dict()
for x, sublist in enumerate(my_list):
data[x] = [mb.BS([120, i, 1, 20 ], 10).callPrice for i in sublist]
and if you feel like you want this shorter (not recommended but some like it) then use a dict comprehension instead of the outer loop:
data = {x: [mb.BS([120, i, 1, 20 ], 10).callPrice for i in sublist]
for x, sublist in enumerate(my_list)}
provided that
my_nested_list = [[1,2,3], [4,5,6,7], [8,9]]
[i for i in my_nested_list]
returns
[[1, 2, 3], [4, 5, 6, 7], [8, 9]]
something along
my_list = [[20, 25, 30, 35, 40, 45], [50, 52, 54, 56, 58, 60, 77, 98, 101],
[30, 40, 50, 60]]
[mb.BS([120, i, 1, 20 ], 10) for i in my_list]
shall return what you expect?

sum of surrounding elements in a list

I'm writing a code which calculates the sum of the numbers beside it.
For example, list1 = [10, 20, 30, 40, 50], the new list = [30 (10+20), 60 (10+20+30), 90 (20+30+40), 120 (30+40+50), 90 (40+50)]. => final list = [30, 60, 90, 120, 90].
At the moment my idea was of using a for loop but it was totally off.
You can do it by creating triplets using zip:
# pad for first and last triplet
lst = [0] + original + [0]
# summarize triplets
sums = [sum(triplet) for triplet in zip(lst, lst[1:], lst[2:])]
Example:
>>> original = [10, 20, 30, 40, 50]
>>> lst = [0] + original + [0]
>>> sums = [sum(triplet) for triplet in zip(lst, lst[1:], lst[2:])]
>>> sums
[30, 60, 90, 120, 90]
>>>
Check out this guy's flatten function What is the fastest way to flatten arbitrarily nested lists in Python?
Take the result of the flattened lists of lists and sum the collection normally with a for loop, or a library that provides a count utility for collections.

Categories