Removing elements from a list using indexs from another - python

I have written a function that collects all index positions of 'NULL' and 'NaN' strings that appear in a list and append them to another list called num. I am now trying to write a function that goes through the list that holds the strings 'NULL' and 'NaN' and uses the index positions from the num list to remove them.
I have coded these so far without success.
l = ['NULL', 32, 43, 'NaN', 45, 89, 11, 'NULL']
num = [0, 3, 7]
def rowRemover():
for i in num:
l.pop(num[i])
rowRemover()
print(l)
def rowRemover():
i = 0
while i < len(num):
l.pop(num[i])
i += 1
rowRemover()
print(l)
I would appreciate your help. Thanks

Instead of popping elements from a list, consider a list comprehension. Since we'll be checking if indices match and checking if an item exists in a set is cheaper than doing the same with a list, convert num to num_set. Then enumerate function will help you identify which elements to exclude:
l = ['NULL', 32, 43, 'NaN', 45, 89, 11, 'NULL']
num_set = set([0, 3, 7])
new_l = [x for i, x in enumerate(l) if i not in num_set]
Output:
[32, 43, 45, 89, 11]

Related

Given a list of integer numbers and a list of indices how can i use map to add 10 to specific elements in the first list?

I want to map a function only to specific elements in a list; those would be the elements of the indices existent in the indices list. I have tried lots of things similar to what I've written here, below. I am trying to achieve this without using the classic for-loop. *edit: by "classic for-loop" I mean using range ( something like: for i in range(len(list)) )
lista = [123, 456, 1, 0, -2, 13, 15, 29, 47, 48]
index_list = [0, 1, 2, 3]
lista = list( map( lambda x: x + 10 if #some condition here I could not figure out#
\ else x for x in list ) )
print(lista)
#expected output: [133, 466, 11, 10, -2, 13, 15, 29, 47, 48]
I have also tried defining my own function and then mapping it, but to no avail. How can I do this?
Assuming that you don't want to use the straight forward solution by iterating the indices list instead:
The problem is that one of the variables you're depending on (the index) is not included in your call to map. You'll have to insert that into the map call in some way, for example by using enumerate - which will emit a (idx, value) tuple for each element in your list.
nums = [123, 456, 1, 0, -2, 13, 15, 29, 47, 48]
indices = [0, 1, 2, 3]
result = list(
map(
lambda x: x[1] + 10 if x[0] in indices else x[1],
enumerate(nums)
)
)
print(result)
Be aware that the if x[0] in indices part will search the indices list linearly, and will make the whole operation O(n * m). This can be optimised by using a set (which has O(1) lookup as the common case) or a dictionary instead.
> [133, 466, 11, 10, -2, 13, 15, 29, 47, 48]

Check if double of element in first list is present in second list and print the output

Suppose
List1 = [ 23, 45, 6, 7, 34]
List2 = [46, 23, 1, 14, 68, 56]
Compare List1 and List2 and print the element of List1 which have a double value in List2
Output = [23,7,34]
Try this:
Output = [i for i in List1 if i*2 in List2]
You can convert list2 to a set for efficient lookups, and use a list comprehension with the said condition for the desired output:
set2 = set(List2)
[i for i in List1 if i * 2 in set2]
You already have the answer but just of the sake of simplicity. Basically you want to iterate through List1 and check if double value is in List2. If so add element to the output array.
List1 = [ 23, 45, 6, 7, 34]
List2 = [46, 23, 1, 7, 14, 68, 56]
output = []
for i in List1:
if i*2 in List2:
output.append(i)
print output
You already got the answers. However, just for fun, I came up with the following method. I did not benchmark all the approaches listed here. It can be fun to do that. This is an interesting question and can be investigated more. However, just for the sake of it I present the solution I did.
import numpy as np
l = np.array(List1) * 2
print(l)
## array([46, 90, 12, 14, 68])
print(set(l) & set(List2))
## {68, 46, 14}
l2 = set(l) & set(List2)
print([List1[list(np.nonzero(l == i))[0][0]] for i in l if i in l2])
## [23, 7, 34]
It uses the broadcasting of numpy along with the fast intersection operation of Python set. This maybe useful if the two lists are very big.

Trying to For Loop a list and append to new list, but it returns after the first item

I'm trying to solve this task:
Loop through list A and create a new list with only items form list A that's between 0-5.
What am I doing wrong here?
a = [100, 1, 10, 2, 3, 5, 8, 13, 21, 34, 55, 98]
def new_list(x):
for item in range(len(x)):
new = []
if x[item] < 5 and x[item] > 0:
(new.append(item))
return new
print(new_list(a))
I'm just getting [1] as an answer.
You return command is inside the loop so as soon as it goes through the first case it returns the value exiting the function.
Here is an example of what your code should look like
a = [100, 1, 10, 2, 3, 5, 8, 13, 21, 34, 55, 98]
def new_list(x):
new = []
for item in range(len(x)):
if x[item] < 5 and x[item] > 0:
new.append(x[item])
return new
print new_list(a)
You can achieve the same result by using a list comprehension
def new_list(x):
return [item for item in x if 0 < item < 5]
You're resetting new to a brand new empty list each time through the loop, which discards any work done in prior iterations.
Also, in the if statement you're calling return, which exits your function immediately, so you never process the remainder of the list.
You probably wanted something like this instead:
def new_list(x):
new = []
for item in x:
if 0 < item < 5:
new.append(item)
return new
Just my recommendation. You could use filter() here instead of a making your own loop.
a = [100, 1, 10, 2, 3, 5, 8, 13, 21, 34, 55, 98]
def new_list(x, low=0, high=5):
return filter(lambda f: f in range(low, high), x)
Filter returns a new list with elements passing a given predicate and it's equivalent to
[item for item in iterable if function(item)]
as per the documentation.
Therefore
print new_list(a)
Results in:
[1, 2, 3, 5]
This way you can check any values such as:
print new_list(a, 5, 10)
[5, 8]
Three errors:
you are reinstantiating new with each iteration of the for loop.
you should return new when the list is finished building, at the end of the function.
You are appending item, but this is your index. In your code, you would have to append x[item].
Code with corrections:
a = [100, 1, 10, 2, 3, 5, 8, 13, 21, 34, 55, 98]
def new_list(x):
new = []
for item in range(len(x)):
if x[item] < 5 and x[item] > 0:
new.append(x[item])
return new
print(new_list(a))
Output:
[1, 2, 3]
Suggestions:
Don't index, loop over the items of x directly (for item in x: ...).
Use chained comparisons, e.g. 0 < item < 5.
Consider a list comprehension.
Code with all three suggestions:
>>> [item for item in a if 0 < item < 5]
>>> [1, 2, 3]
Just a suggestion!
The empty list is inside the For Loop meaning that a new empty list is created every iteration
The 'return' is also inside the for loop which is less than ideal, you want it to be returned after the loop has been exhausted and all suitable elements have been appended.
a = [100, 1, 10, 2, 3, 5, 8, 13, 21, 34, 55, 98]
def new_list(x):
new = []
for item in range(len(x)):
if x[item] < 5 and x[item] > 0:
new.append(item)
return new
print(new_list(a))

Remove items from a list in Python based on previous items in the same list

Say I have a simple list of numbers, e.g.
simple_list = range(100)
I would like to shorten this list such that the gaps between the values are greater than or equal to 5 for example, so it should look like
[0, 5, 10...]
FYI the actual list does not have regular increments but it is ordered
I'm trying to use list comprehension to do it but the below obviously returns an empty list:
simple_list2 = [x for x in simple_list if x-simple_list[max(0,x-1)] >= 5]
I could do it in a loop by appending to a list if the condition is met but I'm wondering specifically if there is a way to do it using list comprehension?
This is not a use case for a comprehension, you have to use a loop as there could be any amount of elements together that have less than five between them, you cannot just check the next or any n amount of numbers unless you knew the data had some very specific format:
simple_list = range(100)
def f(l):
it = iter(l)
i = next(it)
for ele in it:
if abs(ele - i) >= 5:
yield i
i = ele
yield i
simple_list[:] = f(simple_list)
print(simple_list)
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
A better example to use would be:
l = [1, 2, 2, 2, 3, 3, 3, 10, 12, 13, 13, 18, 24]
l[:] = f(l)
print(l)
Which would return:
[1, 10, 18, 24]
If your data is always in ascending order you can remove the abs and just if ele - i >= 5.
If I understand your question correctly, which I'm not sure I do (please clarify), you can do this easily. Assume that a is the list you want to process.
[v for i,v in enumerate(a) if abs(a[i] - a[i - 1]) >= 5]
This gives all elements with which the difference to the previous one (should it be next?) are greater or equal than 5. There are some variations of this, according to what you need. Should the first element not be compared and excluded? The previous implementation compares it with index -1 and includes it if the criteria is met, this one excludes it from the result:
[v for i,v in enumerate(a) if i != 0 and abs(a[i] - a[i - 1]) >= 5]
On the other hand, should it always be included? Then use this:
[v for i,v in enumerate(a) if (i != 0 and abs(a[i] - a[i - 1]) >= 5) or (i == 0)]

python slicing a string of numbers in to sections based on lengths within the string

I have a string of numbers that I want to read from a file and parse into sub-sections, with lengths of the subsections based on numbers within the string. The first number in the string is the length of the first sub-section. So for example, if I have a string of data as follows:
4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77
I want to divide up as follows:
first subsection is length 4, so, 4, 11, 22, 33
second subsection is length 3, so 3, 44, 55
third subsection is length 5, so 5, 44, 55, 66, 77
I tried using variables in slice, so that I could increment the start/stop values as I march through the data, but it doesn't take vars. I worked out a way to delete each subsection as I go so that the first value will always be the length of the next subsection, but it seems sort of clunky.
I'd appreciate any suggestions - thx
You can do something like:
your_list = [4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77]
subsec = []
it = iter(your_list)
for n in it:
subsec.append([n] + map(lambda x: next(it), range(int(n-1))))
This way you only loop once over your list.
or
for n in it:
subsec.append([n] + [next(it) for _ in range(int(n-1))])
When dealing with more complex logic, I prefer to use regular loops.
In this case I would go with a while loop, running until the list is empty, and removing the elements already processed. If the sections are wrong (i.e. the last section goes beyond the size of the string), the assert will tell you.
sequence = [4, 11, 22, 33, 3, 44, 55, 5, 44, 55, 66, 77]
sections = []
while sequence:
section_size = sequence[0]
assert len(sequence) >= section_size
sections.append(sequence[:section_size])
sequence = sequence[section_size:]
print sections
This splits the sections and save them in a list called sections, with the size as first element, like in your examples.
Edit: added error checking.
Just thought I'd throw this out there. Very similar to both BoppreH's solution, but it avoids the overhead of creating n additional lists by iterating over indices:
def generateSlices(seq):
i = 0
while i < len(seq):
n = x[i]
yield x[i:i + n]
i += n
You can check for errors after generating a list of sublists by doing:
mySubLists = [[5, 23, 33, 44, 2], [10]]
all(len(x) == x[0] for x in mySubLists)
Incidentally, why is your data structured in this strange way? It seems error-prone.

Categories

Resources