I want to make a code that receives a random list and stores only positive numbers.
However, if I run it with the code I wrote, I only get positive numbers, but the order is reversed. What should I do?
As an example of the code, [3, 2, 1, 0] is displayed.
I want to print this out [0, 1, 2, 3].
def filter(list):
flist = []
for i in list:
if list[i]>=0:
flist.append(list[i])
else:
continue
return flist
list = [-1,-2,-3,-4,0,1,2,3]
print(filter(list))
for i in list iterates over the items in the list, not the indices. Since the first four items in the list are negative numbers, when you use them as indices, you end up iterating through the last half of the list in reverse order before reaching zero and then iterating through the first half of the list in forward order. (If all the items in the list didn't happen to be valid indices for that same list, you'd just get an IndexError instead.)
To iterate over all the items in the list in order by index use range and len:
# 'filter' and 'list' are both builtin names, don't redefine them
def filter_nat(nums):
flist = []
for i in range(len(nums)):
if nums[i]>=0:
flist.append(nums[i])
else:
continue
return flist
nums = [-1,-2,-3,-4,0,1,2,3]
print(filter_nat(nums)) # [0, 1, 2, 3]
It's simpler to iterate by value, though; you just need to use the value itself rather than trying to use it as an index:
def filter_nat(nums):
flist = []
for i in nums:
if i >=0:
flist.append(i)
return flist
nums = [-1,-2,-3,-4,0,1,2,3]
print(filter_nat(nums)) # [0, 1, 2, 3]
and it's simpler yet to use a comprehension instead of individually appending each item:
def filter_nat(nums):
return [i for i in nums if i >= 0]
nums = [-1,-2,-3,-4,0,1,2,3]
print(filter_nat(nums)) # [0, 1, 2, 3]
sort before returning the list
def filter(list):
flist = []
for i in list:
if list[i]>=0:
flist.append(list[i])
else:
continue
flist.sort()
return flist
list = [-1,-2,-3,-4,0,1,2,3]
print(filter(list))
Output:
[0, 1, 2, 3]
What do you want? Something in the same order as encountered reading from left to right or in increasing order? If it is in the order of reading in initial list, here is the answer:
function append() adds the element at the end of the list. Hence, you could either go over the list from the end to its beginning using append() or going in same order as you, use another fashion in order to add the element at the beginning. When sticking to your code, we would have
def filter(list):
flist = []
for i in list:
if list[i]>=0:
flist = [i] + flist
else:
continue
return flist
However, this could be written way more "pythonic" in the following way:
def filter(list):
return [i for i in list if i>=0]
Try for i in range (len(list)):
You would be looping through the number of items in the list. Personally it is easier and cleaner code for me but everyone has his preferences.
Try:
print(filter(list[::-1]))
Related
I'm trying to make a function, called delta in this case, that will take in an in_list and return and out_list. These are the requirements for the out_list:
len(out_list) == len(in_list)-1
out_list(i) = in_list(i+1)-in_list(i)
I wish to use the function on the lists "times" and "positions" in the code below:
positionfile = open.("positionmeasurements.txt", "r", encoding="utf-8-sig")
filetext = positionfile.read().splitlines()
times = []
positions = []
for i in filetext:
time, position = i.split(";")
times.append(time)
positions.append(position)
This is the code I've got so so far for the function:
def delta(in_list):
for i in in_list:
out_list = in_list[i+1] - in_list[i]
return out_list
The following numbers are the times (left side of the semicolon) and the positions:
0.05;0.9893835
0.1;0.9921275
0.15;0.989212
0.2;0.98784
0.25;0.9876685
0.3;0.988526
0.35;0.991613
0.4;0.9921275
0.45;0.9921275
0.5;0.9886975
0.55;0.985096
0.6;0.983724
0.65;0.9578275
0.7;0.9163245
0.75;0.8590435
0.8;0.7890715
0.85;0.714812
0.9;0.642096
0.95;0.559776
1;0.4776275
1.05;0.398566
1.1;0.315903
1.15;0.2320395
1.2;0.1799035
1.25;0.181104
You can try the list comprehension. As the elements of your list are string, you must convert them into float :
def delta(in_list):
return [float(in_list[i+1]) - float(in_list[i]) for i in range(len(in_list) - 1)]
Part of me thinks it'd be more elegant to do this recursively, but the way you've done it is probably better if there's a very long list. Anyway, you're nearly there, you've just mixed up Python's for-loop syntax. for item in list gives you the items, for i in range(len(list)) gives indices to use with the list, which is what you want here.
def delta(in_list):
out_list = []
for i in range(len(in_list)-1):
out_list.append(in_list[i+1] - in_list[i])
return out_list
Just a list comprehension...
>>> in_list = [1, 1, 2, 3, 5, 8, 13, 21]
>>> [b - a for a, b in zip(in_list, in_list[1:])]
[0, 1, 1, 2, 3, 5, 8]
I am trying to remove duplicates from a sorted list.
nums = [0,0,1,1,1,2,2,3,3,4]
for i in range(len(nums)):
a = nums.count(i)
if(a>1):
nums.pop(i)
I am getting [0, 1, 2, 3, 3, 4] but am expecting [0, 1, 2, 3, 4].
I see the logic I used worked halfway and removed duplicates until the value 2 but for some reason I don't understand it didn't work for the value 3.
Your logic won't exactly work here. Since you're looping through the number of items in the list and the length of the list is changing, you are at risk at running into an error (IndexError).
Here's another way to approach this problem.
nums = [0,0,1,1,1,2,2,3,3,4]
new_list = []
for i in range(len(nums)):
num = nums[i]
if num not in new_list:
new_list.append(num)
print(new_list)
nums = [0,0,1,1,1,2,2,3,3,4]
seen_n = set()
for i, n in reversed(list(enumerate(nums))):
if n in seen_n:
del nums[i]
else:
seen_n.add(n)
print(nums)
Prints:
[0, 1, 2, 3, 4]
If you are iterating the elements by index number, then you need to remove the elements in reverse order so that the indices of the next elements you visit are not affected by the deletions of previous element. In this code we simply keep track of every unique value we see in a set and test each element of the list against membership in that set to see if it should be deleted.
I just wanted to add that there are many ways to solve this problem. But the question posed was, "Remove duplicates from a list." I take this literally and do not consider creating a second list with duplicates removed to be the same thing as removing duplicates from the original list. You have to ask yourself what if there are other references to the original list? Will they see the change? No.
Your problem is in your misunderstanding of nums.pop(i) : it won't delete all the i items, it would delete just that single item having index i.
So that nums.pop(3) deletes the second 2 item.
# [0,0,1,1,1,2,2,3,3,4]
# [ 0,1,1,1,2,2,3,3,4]
# [ 0, 1,1,2,2,3,3,4]
# [ 0, 1, 2,2,3,3,4]
# [ 0, 1, 2, 3,3,4]
This is a different approach, but it may be worth mentioning that you can also remove duplicates by converting to a dict and back.
nums = [0,0,1,1,1,2,2,3,3,4]
nums = list(dict.fromkeys(nums))
There are already lots of answers to this question, but it seems to me none of them are doing the obvious optimization that comes from the fact that the list is sorted, which means that if a number is a duplicate, it is necessarily identical to its predecessor.
This is how I would solve the question, then, using prev_n != n as the most efficient way to know n has not been seen yet:
nums = [0,0,1,1,1,2,2,3,3,4]
uniq_nums = [nums[0]]
prev_n = nums[0]
for n in nums:
if prev_n != n:
uniq_nums.append(n)
prev_n = n
print(uniq_nums)
try using two lists
nums = [0, 1, 2, 2, 3, 4]
nums2 = []
for i in nums:
if i not in nums2: nums2.append(i)
print(nums2)
edit: previous solution was ineffective, whoops
I have an iterator that consists of several lists of the same size. For my purpose I need to know the length of at least one of these lists. But as it is with iterators they can't be accessed the same way as ordinary arrays. So my idea was to get this length by saying:
for i in iter:
list_len = len(i)
break
And this works, however, when using this list later on, and wanting to loop over it again it skips the first iteration, and basically continues from the next iteration from the previous loop (the one above).
Is there some way to fix this ? Or, what is the pythonic way of doing it ?
I was thinking/reading about doing it like:
from itertools import tee
iter_tmp, iter = tee(iter)
for i in iter_tmp:
list_len = len(i)
break
And yeah, that works too, since I can now use the original iter for later use, but it just hurt my eyes that I have to make a loop, import itertools and such just to get the length of a list in an iterator. But maybe that is just the way to go about it ?
UPDATE
Just trying to further explain what I'm doing.
As such iterations is not a list or an array, but in my case, if I were to loop through my iterator I would get something like (in the case of my iterator having four "lists" in it):
>>> for i in iter_list:
print(i)
[1, 2, 5, 3]
[3, 2, 5, 8]
[6, 8, 3, 7]
[1, 4, 6, 1]
Now, all "lists" in the iterator has the same length, but since the lists themselves are calculated through many steps, I really don't know the length in any way before it enters the iterator. If I don't use an iterator I run out of memory - so it is a pro/con solution. But yeah, it is the length of just one of the lists I need as a constant I can use throughout the rest of my code.
That is how iterators work. But you have a few options apart from tee.
You can extract the first element and reuse it when iterating the second time:
first_elem = next(my_iter)
list_len = len(first_elem)
for l in itertools.chain([first_elem], my_iter):
pass
Or if you are going to iterate over the iterator more times, you could perhaps listify it (if it's feasible to fit in memory).
my_list = list(my_iter)
first_len = len(my_list[0])
for l in my_list:
pass
And certainly not the least, as Palivek said, keep/get the information about the length of the lists (from) somewhere else.
In general iterators are not re-iteratable so you'll probably need to store something additional anyway.
class peek_iterator(object):
def __init__(self, source):
self._source = iter(source)
self._first = None
self._sent = False
def __iter__(self):
return self
def next(self):
if self._first is None:
self._first = self._source.next()
if self._sent:
return self._source.next()
self._sent = True
return self._first
def get_isotropic(self, getter):
if self._first is None:
self._first = self._source.next()
return getter(self._first)
lists = [[1, 2, 3], [4, 5, 6]]
i = peek_iterator(lists)
print i.get_isotropic(len) # 3
for j in i: print j # [1, 2, 3]; [4, 5, 6]
You can do a little trick and wrap the original iterator in a generator. This way, you can obtain the first element and "re-yield" it with the generator without consuming the entire iterator. The head() function below returns the first element and a generator that iterates over the original sequence.
def head(seq):
seq_iter = iter(seq)
first = next(seq_iter)
def gen():
yield first
yield from seq_iter
return first, gen()
seq = range(100, 300, 50)
first, seq2 = head(seq)
print('first item: {}'.format(first))
for item in seq2:
print(item)
Output:
first item: 100
100
100
150
200
250
This is conceptually equivalent to Moberg's answer, but uses a generator to "re-assemble" the original sequence instead of itertools.chain().
I'm trying to figure out how to delete an entire list at a specific index if the first element on the inside list meets a certain condition. Below I've shown an example of what I want done but when I run the code I'm getting a list index out of range error in python. If the list[i][0] meets a certain condition I want that entire list delete from the overall list.
list = [[0, 0, 0], [1, 1, 1], [2, 2, 2]]
for i in range(0, len(list)):
if list[i][0] == 0:
del list[i]
return list
Below I've shown a picture of what happens when I run the sample code in IDLE, the first time I run the loop it gives an error but the second time I run the code (copy and pasted both times) it doesn't and it does what I'm asking.
Weird Python Error
Deleting an element from the middle of a list moves everything down, breaking indexing. You need to either remove elements from the end:
for i in range(len(lst)-1, -1, -1):
if lst[i][0] == 0:
del lst[i]
or build a new list and assign it back to the variable, which would also be much more efficient:
lst = [x for x in lst if x[0] != 0]
Try changing your code to this, and 'list' is not a good variable name since it's already a builtin function:
my_list = [[0, 0, 0], [1, 1, 1], [2, 2, 2]]
my_list = [l for l in list if l[0] != 0]
print(my_list)
Usually it's not a good idea to remove elements from list while iterating through it like that because the first time you remove an element the list will no longer be the same length.
1) Create completely new list which will contain elements you want to keep:
listname = [element for element in listname if element[0] != 0]
2) Modify the list you already have (you can do this since lists are mutable):
listname[:] = [element for element in listname if element[0] != 0]
I would recommend using the second approach in case you have references to the same list somewhere else in you program.
Also try not to name your variables list, it's really not a good practice and it probably is not possible since it's keyword.
First, do not ever call your variables list.
Second, a while loop may be a slightly better solution:
stop = range(len(mylist))
i = 0
while i < stop:
if mylist[i][0] == 0:
del mylist[i]
stop -= 1
else:
i += 1
Third, a list comprehension is event better:
[item for item in mylist if item[0] != 0]
It's always bad idea to remove elements from a container while you are iterating over it.
A better approach would be to instead of removing bad elements from the list, copy good ones to a new list:
original = [[0, 0, 0], [1, 1, 1], [2, 2, 2]]
new_list = []
for l in original:
if list[0] != 0:
new_list.append(l)
return new_list
And by the way, "list" is a python keyword and can't be used as variable name.
Or better, use the built-in filter function:
return filter(lambda l : l[0] != 0, original)
I'd make a function in python, that given a list returns a list of list, in which every element is the list given decreased by one.
Input: list_decreaser([0,3,4,5,6,7,8)
Output: [[0,3,4,5,6,7],[0,3,4,5,6],[0,3,4,5],[0,3,4],[0,3],[0]]
My attempt:
def list_decreaser(list):
listresult = []
for x in range(len(list)-1):
list.remove(list[x])
listresult.append(list)
return listresult
The code appends the same list multiple times. It should append copy of the list.
And use del list[..] instead of list.remove(list[..]) to delete an item at specific index.
def list_decreaser(xs):
listresult = []
for i in range(len(xs)-1, 0, -1): # <--- interate backward
del xs[i]
listresult.append(xs[:]) # <----
return listresult
print(list_decreaser([0,3,4,5,6,7,8]))
Or using list comprehension:
>>> xs = [0,3,4,5,6,7,8]
>>> [xs[:i] for i in range(len(xs)-1, 0, -1)]
[[0, 3, 4, 5, 6, 7], [0, 3, 4, 5, 6], [0, 3, 4, 5], [0, 3, 4], [0, 3], [0]]
BTW, don't use list as a variable name. It shadows builtin list function.
The problem is that you're appending the same list over and over again. You keep mutating the list in-place, but you're never creating a new list. So you end up with a list of N references to the same empty list.
This is the same problem discussed in two FAQ questions. I think How do I create a multidimensional list explains it best.
Anyway, what you need to do is append a new list each time through the loop. There are two ways to do that.
First, you can append a copy of the current list, instead of the list itself:
def list_decreaser(list):
listresult = []
for x in range(len(list)-1):
list.remove(list[x])
listresult.append(list[:]) # this is the only change
return listresult
This solves your problem, but it leaves a few new problems:
First, list.remove(list[x]) is a very bad idea. If you give it, say, [0, 1, 2, 0], what happens when you try to remove that second 0? You're calling list.remove(0), and there's no way the list can know you wanted the second 0 rather than the first! The right thing to do is call del list[x] or list.pop(x).
But once you fix that, you're removing the elements from the wrong side. x is 0, then 1, then 2, and so on. You remove element 0, then element 1 (which is the original element 2), then element 2 (which is the original element 4), and eventually get an IndexError. Even if you fixed the "skipping an index" issue (which is also explained in the FAQ somewhere), you'd still be removing the first elements rather than the last ones. You can fix that by turning the range around. However, there's an even easier way: Just remove the last element each time, instead of trying to figure out which x is the right thing, which you can do by specifying -1, or just calling pop with no argument. And then you can use a much simpler loop, too:
def list_decreaser(list):
listresult = []
while list:
list.pop()
listresult.append(list[:])
return listresult
Of course this appends the last, empty list, which you apparently didn't want. You can fix that by doing while len(list) >= 1, or putting an if list: listresult.append(list[:]), or in various other ways.
Alternatively, you can make new truncated lists instead of truncating and copying the same list over and over:
def list_decreaser(list):
listresult = []
while len(list):
list = list[:-1]
listresult.append(list)
return listresult
Note that in this second version, rather than changing the value stored in list, we're creating a new list and storing that new list in list.
use this
def list_decreaser(list1):
listresult = []
for i in list1:
list1 = list[:-1]
listresult.append(list1)
return listresult