Select all possible previous array/list elements - python

I want to select in a for loop the i element of an array/list and store up to the 4 previous elements in a list + the present element. This previous-elements list is thus updated every loop as i advances:
a=list(range(0,50))
for i in range(0,len(a)-1):
previous_4=a[i-4:i+1]
present_element=a[i]
print('The present element is {}'.format(present_element))
print('The previous list is {}'.format(previous_4))
My problem is that when running the for loop, the first 4 loops do not store any previous_4 list, not event the present element, as it is below the 0 index.
The present element is 0
The previous list is []
The present element is 1
The previous list is []
The present element is 2
The previous list is []
The present element is 3
The previous list is []
The present element is 4
The previous list is [0, 1, 2, 3, 4]
The present element is 5
The previous list is [1, 2, 3, 4, 5]
What I want is an output list of any of the 4-previous elements available in a list:
The present element is 0
The previous list is [0]
The present element is 1
The previous list is [0, 1]
The present element is 2
The previous list is [0, 1, 2]
The present element is 3
The previous list is [0, 1, 2, 3]
The present element is 4
The previous list is [0, 1, 2, 3, 4]
The present element is 5
The previous list is [1, 2, 3, 4, 5]
Is there any way to tell Python "catch me any available element of this list up to 4 elements"?

The problem is that your slicing a[i-4:i+1] is wrong because i-4 is negative at the 4 first iterations. In Python, negative index refers to the elements starting from the end of your list with a[-1] being the last element of the list a. Therefore a[-4:0] returns an empty list while a[-4:-1] would return its 3 last elements. Simply change to
previous_4 = a[max(0,i-4):i+1]

try this:
a=list(range(0,8))
previous_4=[]
for i in range(0,len(a)-1):
previous_4.append(i)
present_element=a[i]
print('The present element is {}'.format(present_element))
print('The previous list is {}'.format(previous_4))
if(len(previous_4)==5):
previous_4.pop(0)

This should work:
for i in range(0, len(a)):
if i < 4:
previous_4 = a[ : i+1]
else:
previous_4 = a[i-4: i+1]

#Kefeng91's answer is a good solution (+1) but most of the answers are poor. I'd say there is a better way, the functional way! This is the way I would do it in proper production code. It is efficient, extensible and reusable!
import collections
def get_n_at_a_time(itr, n):
d = collections.deque(maxlen=n) # double ended queue of fixed size
for elem in iterable:
d.append(elem)
yield tuple(d)
for sublist in get_n_at_time(range(50), 4):
print('the current sublist is: {}'.format(list(sublist)))
outputs
the current sublist is: [0]
the current sublist is: [0, 1]
the current sublist is: [0, 1, 2]
the current sublist is: [0, 1, 2, 3]
the current sublist is: [1, 2, 3, 4]
the current sublist is: [2, 3, 4, 5]
the current sublist is: [3, 4, 5, 6]
...

You can just append and pop from the prevous4 list as you itereate through the list
from collections import deque
a=list(range(0,50))
previous_4 = deque([])
for i in range(0,len(a)-1):
previous_4.append(a[i])
if len(previous_4) > 5:
previous_4.popleft()
present_element=a[i]
print('The present element is {}'.format(present_element))
print('The previous list is {}'.format(previous_4))

This works
a=list(range(0,50))
for i in range(0,len(a)-1):
previous_4=a[i-min(4,i):i+1] #here is the change
present_element=a[i]
print('The present element is {}'.format(present_element))
print('The previous list is {}'.format(previous_4))
Explanation:-
In your code, i-4 in previous_4=a[i-4:i+1] goes negative which is not wanted.
i.e. it should be
a[i-4:i+1] only if i>4
or else simply a[0:i+1] or a[i-i, i+1]
This is what I have done.

Related

How to remove some elements from a list and append them at the beginning of the list in Python

Suppose that I have a list that has [0, 1, 2, 3 , 4, 5, 6] in it. I want to remove those elements that are greater than or equal to 3 and add those removed elements to the beginning of the list. So I wrote the code below:
list = [0, 1, 2, 3, 4, 5, 6]
new_list =[]
for number in list:
if number >= 3:
dropped_number = list.pop()
new_list.append(dropped_number)
new_list.sort()
new_list += list
print(new_list)
However, when I ran the code, the result was displayed as [5, 6, 0, 1, 2, 3 , 4]. Could anyone please explain to me at which step I did wrong here?
There are two issues with your code.
the number you obtain with list.pop() is not the one you just checked with your condition (it is merely the last one in the list)
When you reach 3, list.pop() removes 6,
When you reach 4, list.pop() removes 5,
You never reach 5 because you're at the end of what remains of the list at that point.
removing items from a list within a for-loop on the same list will cause the for-loop to skip items or complain that the list changed during iterations. So, even if you were to pop the appropriate number, your loop would miss items.
You also don't need to sort new_list every time you add to it, you can do it once at the end, but that just optimization.
Instead of a for-loop, you could use the sort method with a key parameter that returns a boolean indicating True for elements that do not meet your conditions (i.e that will be shifted to the right). Because Python's sort is stable, this will only place elements in two groups without otherwise changing their relative order.
L = [0, 2, 4, 6, 1, 3, 5]
L.sort(key=lambda x: not x>=3)
print(L) # [4, 6, 3, 5, 0, 2, 1]
If you need a more procedural solution, you can separate the values in two lists that you stick together at the end:
L = [0, 2, 4, 6, 1, 3, 5]
left,right = [], []
for x in L:
if x >= 3: left.append(x)
else: right.append(x)
L = left + right
# [4, 6, 3, 5, 0, 2, 1]
Modifying a list while iterating over it is usually problematic. What if instead you thought of the problem as building a new list out of two subsets of the original list?
>>> old_list = list(range(7))
>>> [i for i in old_list if i >= 3] + [i for i in old_list if i < 3]
[3, 4, 5, 6, 0, 1, 2]
The reason your program doesn't work is because you are modifying the list whilst searching through it. Instead, you can start by adding the elements >= 3 to a new list and then separately appending the elements < 3 to the list. Also, considering you are created a second 'new_list', there is no need to remove the elements from the first list.
Your new code:
list = [0, 1, 2, 3, 4, 5, 6]
new_list = []
# Append numbers greater than 3 to the new list
for number in list:
if number >= 3:
new_list.append(number)
# Append the numbers less than 3 to the new list
new_list += list[0:list.index(new_list[0])]
print(new_list)
Just to note, this method takes a section of the original list from position 0, to the position (.index) of the first item in the new list, which automatically generates the < 3 condition as the first item in the new list corresponds to the items before the >= 3 condition is met.
list[0:list.index(new_list[0])]

How can I increase the value in list

I've wrote the following code
numbers = [1, 2, 3, 4]
lst = [None] * 3
for i in range(0, 3):
lst[i] = numbers[:]
So if I want to increase the value in first lst by 1 and increase the value in second lst my 2 and so on.
Can I solve this question by for loop?
A possible approach:
numbers=[1, 2, 3, 4]
lst = [None] *3
for i in range(0,3):
lst[i] = [x+i+1 for x in numbers]
Here during each iteration we create new lists by adding i+1 to each value in the list, numbers.
For reference this approach is called list comprehension.
You can do this with list comprehension.
numbers = [i+1+a for i,a in enumerate(numbers)]
Where i will be the index number(I added the +1 since it begins with 0), so for index 1 it will add 1, for index 2 it will add 2 and so on..
And a is the value held at the current index.
which will give an output of:
[2, 4, 6, 8]

-1 index in array?

I am trying to use:
num_new = num[i,-1]
to get the last segment of the array. However, it returns [] when i = 0, and num = [3]
Do I have to use like num[i, len(num)]?
Is there any other attention need to pay when using -1 to retrieve array elements?
I think this is not a matter of -1, but python list slicing.
some_list[-n] means nth element of list from end of list, so you will get 5 as a result in following example:
some_list = [1, 3, 5]
last_elem = some_list[-1] # 5
And this is not a core issue of your question.
List slicing in python works with this args:
some_list[_start_:_end_:_step_]
And end th element is exclusive.
So if you are trying to [3][0:-1], this excludes last element and returns empty list.
If you want to get last segment of list, you should slice like this:
some_list = [1, 2, 3, 4, 5]
sliced_list = some_list[3:] # [4, 5]
neg_1_list = some_list[3:-1] # [4]
This will help you.

Why does my program only delete every other character in a list?

So, I don't understand why my output returns [1, 1, 3, 1, 3], when what I want, and thought, was [1,1,1].
the_list = [1, 2, 1, 2, 3, 1, 2, 3, 4]
target = 1
def keep(the_list, target):
index = 0
for x in the_list:
if x != target:
del the_list[index]
else:
pass
index += 1
print(the_list)
When you delete an item from a list at a specific index, all the items after the specified index get moved forward by 1 since there can be no gap in a list, so after you delete the 2 at index 1, for example, in the next iteration x would become 2 at the index 2 when it used to be at index 3, so your own index variable would be pointing to the wrong item.
To delete items from a list in-place, you should instead count backwards from the end of the list so that the re-indexing of the list after you delete an item won't affect the accuracy of your index counter:
def keep(the_list, target):
index = len(the_list) - 1
while index >= 0:
if the_list[index] != target:
del the_list[index]
index -= 1
so that:
the_list = [1, 2, 1, 2, 3, 1, 2, 3, 4]
target = 1
keep(the_list, target)
print(the_list)
would output:
[1, 1, 1]
But keep in mind that deleting an item from a list is inherently inefficient since it has an average time complexity of O(n) for having to move items after the given index, so deleting multiple items from a list becomes quadratic in complexity. It's much more efficient to use list comprehension to construct a new list from the old one by retaining only items that are equal to the target value. So even though the code above shows you how to correctly delete items from a list in-place, you should not actually use it in any production code.
It is gonna be much cleaner if you use list comprehension to check your list elements and return only what you need.
the_list = [1, 2, 1, 2, 3, 1, 2, 3, 4]
target = 1
new_list = [i for i in the_list if i == target]
List comprehensions are much more readable because its intent is explicit. A loop maybe used to do a lot of different things like more complex aggregations or more processing tasks. In contrast, a list comprehension is only meant to do one thing which is build a new list.

Using for loop in Python 3.4 to remove particular element from array

As I am new to programming in Python. I am trying to remove particular elements from array using for loop which looks like
a=[2,3,1,4,1,1,1,5]
n=a.count(1)
for i in range (len(a)-n):
if (a[i]==1):
del a[i]
else:
a[i]=a[i]
print (a)
I want to remove 1 from array a. But, I am getting result as:
[2, 3, 4, 1, 1, 5].
That is 1 still exists in my new array. Can somebody please answer my problem?
try like this:
a = [2,3,1,4,1,1,1,5]
a = [x for x in a if x!=1] # this is called list comprehension
note Never modify list while iterating
Use a while loop and the remove method:
a = [2, 3, 1, 4, 1, 1, 1, 5]
while 1 in a:
a.remove(1)
print a
The real answer to your question (which none of the other answers addresses) is that every time you remove an item, the index i moves past it.
in your case:
a = [2,3,1,4,1,1,1,5]
after deleting the 5th item in the original list, the pointer moves to the 6th item, and the new 5th item (the second 1 in the sequence of three 1s) is skipped.
Regarding the comment never modify a list in a loop, try to implement an in-place algorithm like Fisher-Yates without modifying the list. Never say never. Know what you're doing.
The OP changes the list in-place, not creating a new list.
There are two methods, the second is safe, the first might be faster.
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(len(a)-1, -1, -1):
if a[i] == toremove:
del a[i]
and
a = [2, 3, 1, 4, 1, 1, 1, 5]
toremove = 1
for i in range(a.count(toremove)):
a.remove(toremove)
The second removes the element however many times it exists (before the loop). Since we are not iterating on the list, it is safe to use the remove method.
Both fragments should be O(n) (but haven't done the calculations).
You can copy a and then remove but you cannot iterate over and delete elements from the same list, if your list starts with n elements python will have n pointers to each element so removing elements from the list as your are iterating over it will cause elements to be missed.python has no way of knowing you have removed elements from the list:
a = [2,3,1,4,1,1,1,5]
for ele in a[:]:
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
You can also use reversed which returns and iterator avoiding creating a whole copy of the list at once:
a = [2,3,1,4,1,1,1,5]
for ele in reversed(a):
if ele == 1:
a.remove(1)
print(a)
[2, 3, 4, 5]
Or using a list comprehension with the [:] syntax so we actually update the original object:
a[:] = (ele for ele in a if ele != 1)
All the above are linear operations using a single pass over a.
Actually as the del statement will remove elements from your list , and as the list that you bound in your loop doesn't been update after the first deleting you remove incorrect elements from your list , so if you want to use del you need to make the list name in your loop to reference to new list , that you can use a function for this aim , but as a more python way you can just use a list comprehension:
>>> a=[2,3,1,4,1,1,1,5]
>>> a=[i for i in a if i !=1]
>>> a
[2, 3, 4, 5]
Or you can use filter :
>>> a=[2,3,1,4,1,1,1,5]
>>> a=filter(lambda x: x !=1,a)
>>> a
[2, 3, 4, 5]

Categories