I would like to know how to find the nth term - (n-1)th term within a list. I know it should be very simple, but I'm just having trouble with application. So given the input of [0, 2, 4, 6, 5], the function should return [0, 2, 2, 2, -1]. My solution (which doesn't work) is as follows:
def cost_to_diff (stocks):
for i in range(i+1):
stock[i] = stock[i] - stock[i-1]
print stock
Why doesn't this work as intended?
Your mistake is that you reset the ith element of list, so on the next cycle iteration you access it's changed value.
This will print what you need
def cost_to_diff (stocks):
for i in range(1, len(stocks)):
print stocks[i] - stocks[i-1]
If you want to print a list, then do
def cost_to_diff (stocks):
diff = []
for i in range(1, len(stocks)):
diff.append(stocks[i] - stocks[i-1])
print diff
or
def cost_to_diff (stocks):
print [stocks[i] - stocks[i-1] for i in range(1, len(stocks))]
Also I advice you to try numpy for such tasks. This function will do the job. Especially if you are playing with stock data, numpy will be much faster than lists. Moreover for stock data one usually uses data frames, so pandas is what you need to study, and Series.diff is the function you need.
You are using the wrong range. You need to find out the length of the stocks list, and then build your range accordingly.
differences = []
for i in range(len(stocks) - 1):
differences.append(stock[i+1] - stock[i])
print differences
However, there is a better way to do this. Python has several builtins to help you do this kind of stuff easily. Use the zip function to get your elements without messing around with indexes.
differences = []
for a, b in zip(l, l[:1]):
differences.append(b-a)
For example:
my_list = [0, 3, 4, 5, 7]
print zip(my_list, my_list[1:])
This produces output
[(0, 3), (3, 4), (4, 5), (5, 7)]
All you need to do after is subtract the elements.
The following code returns [2, 2, 2, -1] because I don't get why you will get 0 for the first element.
Do you assume that the first -1 element is also 0?
len('list') will give you the length of list.
range(start, end) will give you a range.
Since you like to start your iterations in the for loop at the second element (index = 1) start will be 1 and end will be the length of the stock list.
stock = [0,2,4,6,5]
result = []#create an empty list for the results
for i in range(1,len(stock)):#set the iteration steps, will be 1,2,3,4 in this case
result.append(stock[i] - stock[i-1])#By using stack[i] = ... you will overwrite the ith element
print result
Related
I was able to get the list to contain the correct number of occurrences for each element; however, the output I am getting is in the wrong order. So my question is: how would I reorder this to match the expected output? (Or write code that outputs what's expected. I would prefer help with fixing the code I wrote, however.)
My code:
def delete_nth(order,max_e):
for i in order:
if i in order:
if order.count(i)>max_e:
order.remove(i)
return order
My Inputs:
order = [1, 2, 3, 1, 1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1], max_e = 3
My output:
[1, 2, 1, 2, 3, 3, 2, 4, 5, 3, 1]
Should equal:
[1, 2, 3, 1, 1, 2, 2, 3, 3, 4, 5]
The prompt:
Alice and Bob were on a holiday. Both of them took many pictures of
the places they've been, and now they want to show Charlie their
entire collection. However, Charlie doesn't like these sessions,
since the motive usually repeats. He isn't fond of seeing the Eiffel
tower 40 times. He tells them that he will only sit during the
session if they show the same motive at most N times. Luckily, Alice
and Bob are able to encode the motive as a number. Can you help them
to remove numbers such that their list contains each number only up
to N times, without changing the order?
Task
Given a list lst and a number N, create a new list that contains each
number of lst at most N times without reordering. For example if N = 2, and the input is [1, 2, 3, 1, 2, 1, 2, 3], you take [1, 2, 3, 1, 2], drop the
next [1, 2] since this would lead to 1 and 2 being in the result 3
times, and then take 3, which leads to [1, 2, 3, 1, 2, 3].
Let's take a look at your code first:
def delete_nth(order, max_e):
for i in order:
if i in order: # this is (or should be) redundant
if order.count(i) > max_e: # note this scans order many times
order.remove(i) # removes the "first" occurrence not the current
return order
Word of warning, removing items from a list while iterating over it is full of pitfalls. For example after we do a remove() and go to the next iteration, are we sure what the "next" i is going to be?
anyways, the main problem is we are removing the items from the start of the list rather than from the end of it. There is also the issue of scanning items many times but we can look at that later.
One option then might be to work on a reversed version of the list:
NOTE: do not use delete_nth_v2() it is just here to illustrate a point
def delete_nth_v2(order, max_e):
order_reversed = list(reversed(order))
for i in order_reversed:
if order_reversed.count(i) > max_e:
order_reversed.remove(i)
return list(reversed(order_reversed))
This looks like it will do the trick a little better, but we actually still have the problem that i is likely NOT what we expect it to be.
to see this, add in a print() statement:
def delete_nth_v2(order, max_e):
order_reversed = list(reversed(order))
for i in order_reversed:
print(i, order_reversed)
if order_reversed.count(i) > max_e:
order_reversed.remove(i)
return list(reversed(order_reversed))
delete_nth_v2([1,2,3,1,2,3,1,2,3,4], 2)
you will see that on the 3rd iteration, we skip what we might have hoped was i == 2 Bummer :-(
Perhaps though there is a way we can track indexes more manually ourselves. This might allow us to also avoid reversing the lists
def delete_nth_v3(order, max_e):
for index in range(len(order) -1, -1, -1):
if order.count(order[index]) > max_e:
order.pop(index)
return order
Now we are getting someplace. This even produces the "correct" result :-) This seems better and is inline with how we started, but there is still the nagging opportunity to not search the entire list for each item in the list.
Why don't we just build a new list while keeping track of how many of each item we have already seen. This trades a little extra space to avoid the repeated searches.
def delete_nth_v4(items, at_most):
counts = {}
keepers = []
for item in items:
if counts.setdefault(item, 0) + 1 <= at_most:
counts[item] += 1
keepers.append(item)
return keepers
Again we get the correct result and this time it is potentially much faster (at least with larger lists) :-)
Finally, if it was me, I would duck being responsible for the space of the "new" list and I would look at yielding the results back to the caller. I would also probably swap out setdefault() for a collections.defaultdict()
import collections
def delete_nth_v5(items, at_most):
counts = collections.defaultdict(int)
for item in items:
if counts[item] < at_most:
counts[item] += 1
yield item
Note we can verify the equivalence via:
import random
motives = [random.randint(0, 100) for _ in range(1_000)]
print(list(delete_nth_v5(motives, 2)) == delete_nth_v4(motives, 2))
You code has few flaws, but the one you should never, ever do (unless you really know what is going on) is removing elements from lists (and other collections) while iterating over it
l = [1, 2, 3, 4, 5]
for el in l:
l.remove(el)
print(l) # it's not empty!
I suggest to iterate over list and count elements (with dict or Counter) while creating new list with elements that has no count bigger than max_e
def delete_nth(order, max_e):
c = Counter()
res = []
for el in order:
if c[el] < max_e:
c[el] += 1
res.append(el)
return res
I was wondering how I could iterate through this list without including the same number twice.
import itertools
def sum_pairs(ints, s):
indexes = []
pair = []
for numbers in itertools.combinations(ints,2):
if sum(numbers) == s:
pair.append(numbers)
for n in numbers:
indexes.append(ints.index(n))
print(pair)
print(indexes)
a = [10, 5, 2, 3, 7, 5]
target = 10
Here's the output:
[(5, 5), (3, 7)]
[1, 1, 3, 4]
'pair' correctly outputs 5 and 5 to equal 10, but when I check where the numbers come from with the variable 'indexes', I can see that the same 5 was used twice and the second five was never taken into consideration. What i'm looking for is how can I modify this to not add the same number twice if it's in the same index. For ex. the output of indexes would be [1, 5, 3, 4].
Thank you so much.
Smuggle the index of each value along with it by using enumerate:
import itertools
def sum_pairs(ints, s):
indexes = []
pair = []
for (ix, x), (iy, y) in itertools.combinations(enumerate(ints),2):
if x + y == s:
pair.append((x, y))
indexes += (ix, iy)
print(pair)
print(indexes)
a = [10, 5, 2, 3, 7, 5]
target = 10
sum_pairs(a, target)
which outputs:
[(5, 5), (3, 7)]
[1, 5, 3, 4]
To simplify the usage of the values, I unpacked the tuple of tuples to names (x and y are the "real" values, ix is the index of x and iy is the index of y). By attaching the index to the value, you always know exactly where it came from, without having to guess at it.
Your use of the index method didn't work because, for all practical purposes, the two 5 in your input are indistinguishable (on CPython, thanks to the small int optimization, they're actually the same object), and index just returns the first one it finds (and has to needlessly rescan for it every time). By keeping the index with the associated value, you don't have to recheck at all, you already know it.
Run combination on the index instead. BTW your indexes is defined not-so-commonly. If you got what I meant, try change the 'extend' with an append below
def sum_pairs(ints, s):
indexes = []
pair = []
for numbers in itertools.combinations(range(len(ints)),2):
if ints[numbers[0]]+ints[numbers[1]] == s:
indexes.extend(numbers)
pair.append((ints[numbers[0]],ints[numbers[1]]))
print(pair)
print(indexes)
My list is a nested list like this:
[[3, 0, 5, 2, 2, 3, 5, 1, 3, 4, 2, 3, 5, 4], etc.
function overunder returns tuple like this: (1,2,3,4,5,6)
worksheet2.write writes results in excel file
I need every function result (tuple) to be written on the new row in excel file
So I came up with the following code
for item in list:
ou = overunder(item)
i = 0
ii = []
s = sum(ii)
while i < len(ou):
worksheet2.write(s + 2, i + 2, ou[i])
i += 1
ii.append(1)
It seems working fine, the only problem I have to increment s with each for loop.
But strangely enough ii doesn't get appended.
What may be wrong?
Your problem is that s and ii get their values re-initialized on each for loop. You want to move ii = [] to be defined before the loop. But anyway, that is a weird way of maintaining s with summing the ii list. Your code could be simplified by using the enumerate function:
for row, item in enumerate(lst):
ou = overunder(item)
for col, element in enumerate(ou):
worksheet2.write(row + 2, col + 2, element)
By the way, you didn't mention what library you are using to write to the excel. Using openpyxl you can take advantage of the append method to write a whole line at once and greatly simplify your code:
for item in lst:
worksheet2.append(('', '') + overunder(item))
Okay, try this:
for i in range(6):
print(i)
This will print numbers from zero to five.
I can't understand your problem, but you are initializing your list with ii = [ ], this will delete the contents of your list. After this you sum([ ])
Hope it is helpful!
I'm looking at getting values in a list with an increment.
l = [0,1,2,3,4,5,6,7]
and I want something like:
[0,4,6,7]
At the moment I am using l[0::2] but I would like sampling to be sparse at the beginning and increase towards the end of the list.
The reason I want this is because the list represents the points along a line from the center of a circle to a point on its circumference. At the moment I iterate every 10 points along the lines and draw a circle with a small radius on each. Therefore, my circles close to the center tend to overlap and I have gaps as I get close to the circle edge. I hope this provides a bit of context.
Thank you !
This can be more complicated than it sounds... You need a list of indices starting at zero and ending at the final element position in your list, presumably with no duplication (i.e. you don't want to get the same points twice). A generic way to do this would be to define the number of points you want first and then use a generator (scaled_series) that produces the required number of indices based on a function. We need a second generator (unique_ints) to ensure we get integer indices and no duplication.
def scaled_series(length, end, func):
""" Generate a scaled series based on y = func(i), for an increasing
function func, starting at 0, of the specified length, and ending at end
"""
scale = float(end) / (func(float(length)) - func(1.0))
intercept = -scale * func(1.0)
print 'scale', scale, 'intercept', intercept
for i in range(1, length + 1):
yield scale * func(float(i)) + intercept
def unique_ints(iter):
last_n = None
for n in iter:
if last_n is None or round(n) != round(last_n):
yield int(round(n))
last_n = n
L = [0, 1, 2, 3, 4, 5, 6, 7]
print [L[i] for i in unique_ints(scaled_series(4, 7, lambda x: 1 - 1 / (2 * x)))]
In this case, the function is 1 - 1/2x, which gives the series you want [0, 4, 6, 7]. You can play with the length (4) and the function to get the kind of spacing between the circles you are looking for.
I am not sure what exact algorithm you want to use, but if it is non-constant, as your example appears to be, then you should consider creating a generator function to yield values:
https://wiki.python.org/moin/Generators
Depending on what your desire here is, you may want to consider a built in interpolator like scipy: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html#scipy.interpolate.interp1d
Basically, given your question, you can't do it with the basic slice operator. Without more information this is the best answer I can give you :-)
Use the slice function to create a range of indices. You can then extend your sliced list with other slices.
k = [0,1,2,3,4,5,6,7]
r = slice(0,len(k)//2,4)
t = slice(r.stop,None,1)
j = k[r]
j.extend(k[t])
print(j) #outputs: [0,4,5,6,7]
What I would do is just use list comprehension to retrieve the values. It is not possible to do it just by indexing. This is what I came up with:
l = [0, 1, 2, 3, 4, 5, 6, 7]
m = [l[0]] + [l[1+sum(range(3, s-1, -1))] for s in [x for x in range(3, 0, -1)]]
and here is a breakdown of the code into loops:
# Start the list with the first value of l (the loop does not include it)
m = [l[0]]
# Descend from 3 to 1 ([3, 2, 1])
for s in range(3, 0, -1):
# append 1 + sum of [3], [3, 2] and [3, 2, 1]
m.append(l[ 1 + sum(range(3, s-1, -1)) ])
Both will give you the same answer:
>>> m
[0, 4, 6, 7]
I made this graphic that would I hope will help you to understand the process:
I am analysing data using Python and I have a list of N 2d data arrays. I would like to look at these elements one by one and compare them to the average of the other N-1 elements.
Is there a built-in method in Python to loop over a list and have on one hand a single element and on the other the rest of the list.
I know how to do it the ``ugly'' way by looping over an integer and joining the left and right part:
for i in xrange(N):
my_element = my_list[i]
my_sublist = my_list[:i] + my_list[i+1:]
but is there a Pythonista way of doing it?
We can calculate the sum of all elements. Then we can easily for each element find the sum of the rest of the elements. We subtract from the total sum the value of the current element and then in order to find the average we divide by N - 1:
s = sum(my_list)
for my_element in my_list:
avg_of_others = (s - my_element) / float(len(my_list) - 1)
...
EDIT:
This is an example how it can be extended to numpy:
import numpy as np
l = np.array([(1, 2), (1, 3)])
m = np.array([(3, 1), (2, 4)])
my_list = [l, m]
s = sum(my_list)
for my_element in my_list:
avg_of_others = (s - my_element) / float(len(my_list) - 1)
Nothing built-in that I know of, but maybe a little less copy-intensive using generators:
def iwithout(pos, seq):
for i, elem in enumerate(seq):
if i != pos:
yield elem
for elem, others in (elem, iwithout(i, N) for i, elem in enumerate(N)):
...
# others is now a generator expression running over N
# leaving out elem
I would like to look at these elements one by one and compare them to the average of the other N-1 elements.
For this specific use case, you should just calculate the sum of the entire list once and substract the current element to calculate the average, as explained in JuniorCompressor's answer.
Is there a built-in method in Python to loop over a list and have on one hand a single element and on the other the rest of the list.
For the more general problem, you could use collections.deque to pop the next element from the one end, giving you that element and the remaining elements from the list, and then add it back to the other end before the next iteration of the loop. Both operations are O(1).
my_queue = collections.deque(my_list)
for _ in enumerate(my_list):
my_element = my_queue.popleft() # pop next my_element
my_sublist = my_queue # rest of queue without my_element
print my_element, my_sublist # do stuff...
my_queue.append(my_element) # re-insert my_element
Sample output for my_list = range(5):
0 deque([1, 2, 3, 4])
1 deque([2, 3, 4, 0])
2 deque([3, 4, 0, 1])
3 deque([4, 0, 1, 2])
4 deque([0, 1, 2, 3])