How to create new array deducting segments of existing array - python

I am trying to create new array out of an existing array in Python.
I read some of already existing and similar questions but I still can not solve the problem.
For example:
I have array A = [4,6,9,15] and I want to create B =[(6-4),(9-6),(15-9)].
I tried to do it in for loop like this:
deltaB=[]
for i in range(0,len(A)):
deltaB[i]=A[i]-A[i-1]
deltaB.append(deltaB[i])
But that does not work... probably because I am writing code completely wrong since I'm new in Python and programming in general.
Can you help and write me code for this?
Many thanks upfront

List comprehension
Probably the best way to do this is using list comprehension:
[xj-xi for xi,xj in zip(A,A[1:])]
which generates:
>>> [xj-xi for xi,xj in zip(A,A[1:])]
[2, 3, 6]
Here we first zip(..) A (the list) and A[1:] the slice of the list that omits the first element together into tuples. For each such tuple (xi,xj) we add xj-xi to the list.
The error
The error occurs because in the for loop, you start from 0 and stop before len(A), it should be starting from 1 and stop before len(A). Furthermore you cannot first assign to an index that does not exist, you need to directly append it:
deltaB=[]
for i in range(1,len(A)):
deltaB.append(A[i]-A[i-1])

Related

How to keep on updating a specific list within the for loop?

I'm very new to the world of programming, I've been trying to solve a specific python academic exercise but I ran into an obstacle.
The problem is that I need to generate a lucky numbers sequence, as in the user inputs a sequence [1,...,n] and these steps happen:
Every second element is removed
Every third element is removed
Every fourth element is removed
.
.
.
When it becomes impossible to remove more numbers, the numbers left in the list are "lucky".
This is my code:
def lucky(l):
index = 2
new_list = []
while(index<len(l)):
for i in range(len(l)):
if(i%index==0):
new_list.append(l[i])
index=index+1
return new_list
The while loop is to have the final condition when " it is impossible to remove more numbers". However with every iteration, the list gets shorter more and more, but I don't know how to do it.
My code works for the first condition when index=2(remove every 2nd element), then in the following loops it doesn't work because:
It is still limited by length of the original list.
new_list.append(l[i]) will just add more elements to the new_list, rather than updating it in its place.
I don't know how to update the list without creating multiple amounts of lists and with each iteration adding the new elements to a new list.
Any help is appreciated.
You could use del with appropriate list slicing (see the manual for more details) to update the list in-place:
def lucky(l):
interval = 2
while interval <= len(l):
del l[interval-1::interval]
interval += 1
I am not sure if I understand your question correctly, but you can remove items from your original list via del l[index], where index is the index of the element to be removed.
For more details on lists look here:
https://docs.python.org/3/tutorial/datastructures.html
import math
def lucky(l, index):
for i in range(math.floor(len(l)/index)):
del l[(i+1)*(index-1)]
Not sure if the code will work, as I cannot test it right now. But I think it should work somehow like that.
EDIT:
Tested it and the code works. If you want to run all three steps, just do:
l = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
lucky(l,2)
lucky(l,3)
lucky(l,4)
print(l)
>>>[1,3,7,13,15]

Reduce a list in a specific way

I have a list of strings which looks like this:
['(num1, num2):1', '(num3, num4):1', '(num5, num6):1', '(num7, num8):1']
What I try to achieve is to reduce this list and combine every two elements and I want to do this until there is only one big string element left.
So the intermediate list would look like this:
['((num1, num2):1,(num3, num4):1)', '((num5, num6):1,(num7, num8):1)']
The complicated thing is (as you can see in the intermediate list), that two strings need to be wrapped in paranthesis. So for the above mentioned starting point the final result should look like this:
(((num_1,num_2):1,(num_3,num_4):1),((num_5,num_6):1,(num_7,num_8):1))
Of course this should work in a generic way also for 8, 16 or more string elements in the starting list. Or to be more precise it should work for an=2(n+1).
Just to be very specific how the result should look with 8 elements:
'((((num_1,num_2):1,(num_3,num_4):1),((num_5,num_6):1,(num_7,num_8):1)),(((num_9,num_10):1,(num_11,num_12):1),((num_13,num_14):1,(num_15,num_16):1)))'
I already solved the problem using nested for loops but I thought there should be a more functional or short-cut solution.
I also found this solution on stackoverflow:
import itertools as it
l = [map( ",".join ,list(it.combinations(my_list, l))) for l in range(1,len(my_list)+1)]
Although, the join isn't bad, I still need the paranthesis. I tried to use:
"{},{}".format
instead of .join but this seems to be to easy to work :).
I also thought to use reduce but obviously this is not the right function. Maybe one can implement an own reduce function or so?
I hope some advanced pythonics can help me.
Sounds like a job for the zip clustering idiom: zip(*[iter(x)]*n) where you want to break iterable x into size n chunks. This will discard "leftover" elements that don't make up a full chunk. For x=[1, 2, 3], n=2 this would yield (1, 2)
def reducer(l):
while len(l) > 1:
l = ['({},{})'.format(x, y) for x, y in zip(*[iter(l)]*2)]
return l
reducer(['(num1, num2):1', '(num3, num4):1', '(num5, num6):1', '(num7, num8):1'])
# ['(((num1, num2):1,(num3, num4):1),((num5, num6):1,(num7, num8):1))']
This is an explanation of what is happening in zip(*[iter(l)]*2)
[iter(l)*2] This creates an list of length 2 with two times the same iterable element or to be more precise with two references to the same iter-object.
zip(*...) does the extracting. It pulls:
Loop
the first element from the first reference of the iter-object
the second element from the second reference of the iter-object
Loop
the third element from the first reference of the iter-object
the fourth element from the second reference of the iter object
Loop
the fifth element from the first reference of the iter-object
the sixth element from the second reference of the iter-object
and so on...
Therefore we have the extracted elements available in the for-loop and can use them as x and y for further processing.
This is really handy.
I also want to point to this thread since it helped me to understand the concept.

Delete rows in matrix containing certain elements (python)

The following problem I have, might be very trivial for a more advanced python programmer, but I -- as a python beginner -- can't figure out the problem.
I just want to delete a row from a 2D-list, if it matches a certain condition --- in my case, if the row contains a certain character. I wanted to do it in a more functional, python way, rather than looping over all list items. Therefore, my attempt was
alist = [[1,2],[3,4]]
map(lambda ele : (if 2 in ele: tmp3.remove(ele)), alist)
which should just delete the first row, because it contains a "2". But I just get an error "invalid syntax" and I don't know why!
(I also came across some solution which uses dataframes from the pandas package, but as I'm learning python, I want to avoid pandas at this stage ;) )
Thanks in advance!
You can't use an if statement in a lambda. You could use the more clearer list comprehension:
alist = [row for row in alist if 2 not in row]
This also has the advantage of iterating through the list once, as opposed to using map and list.remove, although you get a new list.
If you are trying to remove elements from a list, you need filter instead of map which is often used for transformation and doesn't change the length of the list:
alist = [[1,2],[3,4]]
filter(lambda ele : 2 not in ele, alist)
# [[3, 4]]

Most pythonic way to truncate a list to N indices when you can't guarantee the list is at least N length?

What is the most pythonic way to truncate a list to N indices when you can not guarantee the list is even N length? Something like this:
l = range(6)
if len(l) > 4:
l = l[:4]
I'm fairly new to python and am trying to learn to think pythonicly. The reason I want to even truncate the list is because I'm going to enumerate on it with an expected length and I only care about the first 4 elements.
Python automatically handles, the list indices that are out of range gracefully.
In [5]: k = range(2)
In [6]: k[:4]
Out[6]: [0, 1]
In [7]: k = range(6)
In [8]: k[:4]
Out[8]: [0, 1, 2, 3]
BTW, the degenerate slice behavior is explained in The Python tutorial. That is a good place to start because it covers a lot of concepts very quickly.
You've got it here:
lst = lst[:4]
This works regardless of the number of items in the list, even if it's less than 4.
If you want it to always have 4 elements, padding it with (say) zeroes or None if it's too short, try this:
lst = (lst + [0] * 4)[:4]
When you have a question like this, it's usually feasible to try it and see what happens, or look it up in the documentation.
It's bad idea to name a variable list, by the way; this will prevent you from referring to the built-in list type.
All of the answers so far don't truncate the list. They follow your example in assigning the name to a new list which contains the first up to 4 elements of the old list. To truncate the existing list, delete elements whose index is 4 or higher. This is done very simply:
del lst[4:]
Moving on to what you really want to do, one possibility is:
for i, value in enumerate(lst):
if i >= 4:
break
do_something_with(lst, i, value)
I think the most pythonic solution that answers your question is this:
for x in l[:4]:
do_something_with(x)
The advantages:
It's the most succinct and descriptive way of doing what you're after.
I suggest that the pythonic way to do this is to slice the source array rather than truncate it. Once you remove elements from the source array they are gone forever, and while in your trivial example that's fine, I think in general it's not a great practice.
Slicing the array to the first four is almost certainly more efficient than removing a possibly large number of elements from its tail.

How do I create a list with 256 elements?

I've started teaching myself Python, and as an exercise I've set myself the task of generating lookup tables I need for another project.
I need to generate a list of 256 elements in which each element is the value of math.sin(2*i*pi/256). The problem is, I don't know how to generate a list initialized to "dummy" values that I can then use a for loop to step through and assign the values of the sin function.
Using list() seems to create an "empty" list, but with no elements so I get a "list assignment index out of range" error in the loop. Is there a way to this other than explicitly creating a list declaration containing 256 elements all with "0" as a value?
Two answers have already shown you how to build your list at a single stroke, using the "list comprehension" (AKA "listcomp") construct.
To answer your specific question, though,
mylist = [None] * 256
is the simplest way to make a list with 256 items, all None, in case you want to fill it in later.
If you start with an empty list, call its .append(...) method to add each item at the end. A loop doing nothing but append on an initially-empty list is what normally gets replaced with a more concise listcomp.
Of course, for the task you actually state,
mylist = [math.sin(2 * math.pi/256)] * 256
would be by far the best approach -- no sense computing a sin 256 times when the argument's always the same (daringly assuming that what you say is what you mean;-).
my_list = [math.sin(2 * math.pi/256) for i in xrange(256)]
You can also try:
l = []
for i in range(256):
l.append(math.sin(2*math.pi/256))
This is an iterative for loop that keeps adding the same value to the end of the list 256 times
I need to generate a list of 256
elements in which each element is the
value of math.sin(2*math.pi/256)
To answer your question literally:
my_list=[math.sin(2*math.pi/256)]*256
Thanks for the help, everyone. I did make a mistake in the specification I posted for the question, in that the value of each element in the list needs to be the sin of the angle incremented by 2*pi/256 each time. The code that works for me in that case is:
li = [math.sin((2*math.pi/256)*i) for i in xrange(0,256)]

Categories