Removing item from a list by a variable - python

Basicly im having problem with deleting an item from a list.
I'd like to to do it by a variable , somehow like this :
my_list = ["cat","dog","duck","horse","snake"]
import random
animal=(random.choice(my_list))
new_list = []
new_list.append(my_list)
new_list.remove(animal)
print(new_list)
and i get this :
ValueError : list.remove(x) : x not in list
What would you guys recommend me?

You've picked a random item from your list and then added the entire old list as a single element in your new list. This creates a two-dimensional list that does not contain any string values in the outermost list.
The best way to debug this is to print your list to see what it contains before applying the removal:
print(new_list) # => [['cat', 'dog', 'duck', 'horse', 'snake']]
Did you notice the extra [[]]? That's a nested list.
Likely, your intent was to copy the list (done here using the slice operator):
my_list = ["cat","dog","duck","horse","snake"]
import random
animal=(random.choice(my_list))
new_list = my_list[:]
new_list.remove(animal)
print(new_list)
Beyond this, it's good practice to include spaces, remove unnecessary parentheses and put imports at the top of files.
Lastly, remove is a linear operation that looks at potentially every element in the list to find the element you want to remove. This may seem silly, but when you begin working with lists of thousands or millions of items, it becomes a huge problem to walk the list unnecessarily.
Try using pop and random.randint to pick an index and remove it from the list in one stroke (you'll still incur a penalty for shifting list members around to fill in the gap; removing from the middle of a list isn't ideal):
import random
my_list = ["cat", "dog", "duck", "horse", "snake"]
new_list = my_list[:]
new_list.pop(random.randint(0, len(my_list) - 1))
print(new_list)

The above answer is adequate. However, I would point out that you can debug code another way, that being:
import pdb
and invoking in your function:
pdb.set_trace()
This basically allows you to enter the debugger at the calling stack frame. I find it much more resourceful.

Related

How to divide the alphabet into lists of letters in a different way

I should divide the alphabet into lists of letters. I done that, my solution is good but my mentor said to me that I should a little improve this solution.
This is my code:
import string
import random
def generate_list():
list_of_letters=list(string.ascii_lowercase)
number_of_letter = len(list_of_letters)
main_list = []
while number_of_letter > 0:
a = random.randint(4, 7)
number_of_letter -= a
main_list.append(list_of_letters[0:a])
del list_of_letters[0:a]
print(main_list)
generate_list()
My mentor said me that I should take and remove lists of letters in one function, not to manually delete these pieces with lists of all letters manually using the del function So he would like to replace this fragment of code in one line.
main_list.append(list_of_letters[0:a])
del list_of_letters[0:a]
Can someone help me? Thank you in advance :)
You can use the pop() function of lists. It returns one item of the list and removes it from the list.
As it removes from the right side, in your case you have to specifically tell to take the list item at index 0 by calling pop(0).
So replacing your two lines from above with the following snippet should do everything in one step:
main_list.append([list_of_letters.pop(0) for _ in range(min(len(list_of_letters), a))])
Please note, that I stop popping elements from list_of_letters if a is larger then the remaining items in it, hence the min(len(list_of_letters), a).

How exactly does Python check through a list?

I was doing one of the course exercises on codeacademy for python and I had a few questions I couldn't seem to find an answer to:
For this block of code, how exactly does python check whether something is "in" or "not in" a list? Does it run through each item in the list to check or does it use a quicker process?
Also, how would this code be affected if it were running with a massive list of numbers (thousands or millions)? Would it slow down as the list size increases, and are there better alternatives?
numbers = [1, 1, 2, 3, 5, 8, 13]
def remove_duplicates(list):
new_list = []
for i in list:
if i not in new_list:
new_list.append(i)
return new_list
remove_duplicates(numbers)
Thanks!
P.S. Why does this code not function the same?
numbers = [1, 1, 2, 3, 5, 8, 13]
def remove_duplicates(list):
new_list = []
new_list.append(i for i in list if i not in new_list)
return new_list
In order to execute i not in new_list Python has to do a linear scan of the list. The scanning loop breaks as soon as the result of the test is known, but if i is actually not in the list the whole list must be scanned to determine that. It does that at C speed, so it's faster than doing a Python loop to explicitly check each item. Doing the occasional in some_list test is ok, but if you need to do a lot of such membership tests it's much better to use a set.
On average, with random data, testing membership has to scan through half the list items, and in general the time taken to perform the scan is proportional to the length of the list. In the usual notation the size of the list is denoted by n, and the time complexity of this task is written as O(n).
In contrast, determining membership of a set (or a dict) can be done (on average) in constant time, so its time complexity is O(1). Please see TimeComplexity in the Python Wiki for further details on this topic. Thanks, Serge, for that link.
Of course, if your using a set then you get de-duplication for free, since it's impossible to add duplicate items to a set.
One problem with sets is that they generally don't preserve order. But you can use a set as an auxilliary collection to speed up de-duping. Here is an illustration of one common technique to de-dupe a list, or other ordered collection, which does preserve order. I'll use a string as the data source because I'm too lazy to type out a list. ;)
new_list = []
seen = set()
for c in "this is a test":
if c not in seen:
new_list.append(c)
seen.add(c)
print(new_list)
output
['t', 'h', 'i', 's', ' ', 'a', 'e']
Please see How do you remove duplicates from a list whilst preserving order? for more examples. Thanks, Jean-François Fabre, for the link.
As for your PS, that code appends a single generator object to new_list, it doesn't append what the generate would produce.
I assume you alreay tried to do it with a list comprehension:
new_list = [i for i in list if i not in new_list]
That doesn't work, because the new_list doesn't exist until the list comp finishes running, so doing in new_list would raise a NameError. And even if you did new_list = [] before the list comp, it won't be modified by the list comp, and the result of the list comp would simply replace that empty list object with a new one.
BTW, please don't use list as a variable name (even in example code) since that shadows the built-in list type, which can lead to mysterious error messages.
You are asking multiple questions and one of them asking if you can do this more efficiently. I'll answer that.
Ok let's say you'd have thousands or millions of numbers. From where exactly? Let's say they were stored in some kind of txtfile, then you would probably want to use numpy (if you are sticking with Python that is). Example:
import numpy as np
numbers = np.array([1, 1, 2, 3, 5, 8, 13], dtype=np.int32)
numbers = np.unique(numbers).tolist()
This will be more effective (above all memory-efficient compared) than reading it with python and performing a list(set..)
numbers = [1, 1, 2, 3, 5, 8, 13]
numbers = list(set(numbers))
You are asking for the algorithmic complexity of this function. To find that you need to see what is happening at each step.
You are scanning the list one at a time, which takes 1 unit of work. This is because retrieving something from a list is O(1). If you know the index, it can be retrieved in 1 operation.
The list to which you are going to add it increases at worst case 1 at a time. So at any point in time, the unique items list is going to be of size n.
Now, to add the item you picked to the unique items list is going to take n work in the worst case. Because we have to scan each item to decide that.
So if you sum up the total work in each step, it would be 1 + 2 + 3 + 4 + 5 + ... n which is n (n + 1) / 2. So if you have a million items, you can just find that by applying n = million in the formula.
This is not entirely true because of how list works. But theoretically, it would help to visualize this way.
to answer the question in the title: python has more efficient data types but the list() object is just a plain array, if you want a more efficient way to search values you can use dict() which uses a hash of the object stored to insert it into a tree which i assume is what you were thinking of when you mentioned "a quicker process".
as to the second code snippet:
list().append() inserts whatever value you give it to the end of the list, i for i in list if i not in new_list is a generator object and it inserts that generator as an object into the array, list().extend() does what you want: it takes in an iterable and appends all of its elements to the list

Removing sublists from a list of lists

I'm trying to find the fastest way to solve this problem, say I have a list of lists:
myList = [[1,2,3,4,5],[2,3],[4,5,6,7],[1,2,3],[3,7]]
I'd like to be able to remove all the lists that are sublists of one of the other lists, for example I'd like the following output:
myList = [[1,2,3,4,5],[4,5,6,7],[3,7]]
Where the lists [2,3] and [1,2,3] were removed because they are completely contained in one of the other lists, while [3,7] was not removed because no single list contained all those elements.
I'm not restricted to any one data structure, if a list of lists or a set is easier to work with, that would be fine too.
The best I could come up with was something like this but it doesn't really work because I'm trying to remove from a list while iterating over it. I tried to copy it into a new list but somehow I couldn't get it working right.
for outter in range(0,len(myList)):
outterSet = set(myList[outter])
for inner in range(outter,len(myList)):
innerSet = set(myList[inner])
if innerSet.issubset(outterSet):
myList.remove(innerSet)
Thanks.
The key to solving your problem is a list of sets:
lists = [[1,2,3,4,5],[2,3],[4,5,6,7],[1,2,3],[3,7]]
sets = [set(l) for l in lists]
new_list = [l for l,s in zip(lists, sets) if not any(s < other for other in sets)]
This converts the inner lists to sets, compares each set to every other set to see if it is contained within it (using the < operator) and, if it is not strictly contained within another set, adds the original list to the new list of lists.

Modify the list that is being iterated in python

I need to update a list while it is being iterated over.
Basically, i have a list of tuples called some_list Each tuple contains a bunch of strings, such as name and path. What I want to do is go over every tuple, look at the name, then find all the tuples that contain the string with an identical path and delete them from the list.
The order does not matter, I merely wish to go over the whole list, but whenever I encounter a tuple with a certain path, all tuples (including oneself) should be removed from the list. I can easily construct such a list and assign it to some_list_updated, but the problem seems to be that the original list does not update...
The code has more or less the following structure:
for tup in some_list[:]:
...
...somecode...
...
some_list = some_list_updated
It seems that the list does update appropriately when I print it out, but python keeps iterating over the old list, it seems. What is the appropriate way to go about it - if there is one? Thanks a lot!
You want to count the paths using a dictionary, then use only those that have a count of 1, then loop using a list comprehension to do the final filter. Using a collections.Counter() object makes the counting part easy:
from collections import Counter
counts = Counter(tup[index_of_path] for tup in some_list)
some_list = [tup for tup in some_list if counts[tup[index_of_path]] == 1]

How to get random slice of python list of constant size. (smallest code)

Hi I have a List say 100 items, now i want a slice of say 6 items which should be randomly selected. Any way to do it in very simple simple concise statement???
This is what i came up with (but it will fetch in sequence)
mylist #100 items
N=100
L=6
start=random.randint(0,N-L);
mylist[start:start+L]
You could use the shuffle() method on the list before you slice.
If the order of the list matters, just make a copy of it first and slice out of the copy.
mylist #100 items
shuffleList = mylist
L=6
shuffle(shuffleList)
start=random.randint(0,len(shuffleList)-L);
shuffleList[start:start+L]
As above, you could also use len() instead of defining the length of the list.
As THC4K suggested below, you could use the random.sample() method like below IF you want a set of random numbers from the list (which is how I read your question).
mylist #100 items
L=6
random.sample(mylist, L)
That's a lot tidier than my first try at it!

Categories