Printing out 2d list in python 2.7 - python

I'm sorry for such a stupid question, I'm not used to object-oriented programming (I come from a C background). To put it bluntly, I'm very clueless on classes. First of all, is this how you initialize a list attribute and set each element to None?
class World:
def __init__(self):
self.arr = [[None for x in range(20)] for y in range(20)]
Also, I wanted to check if each value was, in fact, set to none but I don't know how to print it out.

Since you accepted the answer I can't delete it, so I will try to amend it.
This is the wrong way:
mylist = [[None] * 2] * 2 # Definitely not what you want
The above is bad because if you do
mylist[0].append(1)
The output will be
[[None, None, 1], [None, None, 1]]
The reason is that we didn't create a list of 2 lists, but a list with 2
references to the same list.
The correct way would either be what you already have or:
mylist = [[None] * 20 for i in range(20)]
I am not sure what you mean by "wanted to check if it was set to None".
Something like this for example?
w = World() # make a world instance
print w.arr # This should print your 2d list

Related

Can I not put a for loop inside a for loop like this? [duplicate]

I'm currently developing a program in python and I just noticed that something was wrong with the foreach loop in the language, or maybe the list structure. I'll just give a generic example of my problem to simplify, since I get the same erroneous behavior on both my program and my generic example:
x = [1,2,2,2,2]
for i in x:
x.remove(i)
print x
Well, the problem here is simple, I though that this code was supposed to remove all elements from a list. Well, the problem is that after it's execution, I always get 2 remaining elements in the list.
What am I doing wrong? Thanks for all the help in advance.
Edit: I don't want to empty a list, this is just an example...
This is a well-documented behaviour in Python, that you aren't supposed to modify the list being iterated through. Try this instead:
for i in x[:]:
x.remove(i)
The [:] returns a "slice" of x, which happens to contain all its elements, and is thus effectively a copy of x.
When you delete an element, and the for-loop incs to the next index, you then skip an element.
Do it backwards. Or please state your real problem.
I think, broadly speaking, that when you write:
for x in lst:
# loop body goes here
under the hood, python is doing something like this:
i = 0
while i < len(lst):
x = lst[i]
# loop body goes here
i += 1
If you insert lst.remove(x) for the loop body, perhaps then you'll be able to see why you get the result you do?
Essentially, python uses a moving pointer to traverse the list. The pointer starts by pointing at the first element. Then you remove the first element, thus making the second element the new first element. Then the pointer move to the new second – previously third – element. And so on. (it might be clearer if you use [1,2,3,4,5] instead of [1,2,2,2,2] as your sample list)
Why don't you just use:
x = []
It's probably because you're changing the same array that you're iterating over.
Try Chris-Jester Young's answer if you want to clear the array your way.
I know this is an old post with an accepted answer but for those that may still come along...
A few previous answers have indicated it's a bad idea to change an iterable during iteration. But as a way to highlight what is happening...
>>> x=[1,2,3,4,5]
>>> for i in x:
... print i, x.index(i)
... x.remove(i)
... print x
...
1 0
[2, 3, 4, 5]
3 1
[2, 4, 5]
5 2
[2, 4]
Hopefully the visual helps clarify.
I agree with John Fouhy regarding the break condition. Traversing a copy of the list works for the remove() method, as Chris Jester-Young suggested. But if one needs to pop() specific items, then iterating in reverse works, as Erik mentioned, in which case the operation can be done in place. For example:
def r_enumerate(iterable):
"""enumerator for reverse iteration of an iterable"""
enum = enumerate(reversed(iterable))
last = len(iterable)-1
return ((last - i, x) for i,x in enum)
x = [1,2,3,4,5]
y = []
for i,v in r_enumerate(x):
if v != 3:
y.append(x.pop(i))
print 'i=%d, v=%d, x=%s, y=%s' %(i,v,x,y)
or with xrange:
x = [1,2,3,4,5]
y = []
for i in xrange(len(x)-1,-1,-1):
if x[i] != 3:
y.append(x.pop(i))
print 'i=%d, x=%s, y=%s' %(i,x,y)
If you need to filter stuff out of a list it may be a better idea to use list comprehension:
newlist = [x for x in oldlist if x%2]
for instance would filter all even numbers out of an integer list
The list stored in the memory of a computer. This deals with the pointer to a memory artifact. When you remove an element, in a by-element loop, you are then moving the pointer to the next available element in the memory address
You are modifying the memory and iterating thru the same.
The pointer to the element moves through the list to the next spot available.
So in the case of the Size being 5...enter code here
[**0**,1,2,3,4]
remove 0 ---> [1,**2**,3,4] pointer moves to second index.
remove 2 ---> [1,3,**4**] pointer moves to 3rd index.
remove 4 ---> [1,3]
I was just explaining this to my students when they used pop(1). Another very interesting side-effect error.
x=[1,**2**,3,4,5]
for i in x:
x.pop(1)
print(x,i)
[1, **3**, 4, 5] 1 at index 0 it removed the index 1 (2)
[1, **4**, 5] 3 at index 1 it removed the index 1 (3)
[1, 5] 5 at index 2 it removed the index 1 (4)
heh.
They were like why isnt this working... I mean... it did... exactly what you told it to do. Not a mind reader. :)

Python procedure that uses another procedure returns none

I very new with python and I'm doing an online class to learn the basics. While everything is going well, there are still a things that I don't seem to grasp in python..
Even though I found a much simpler way to solve the bellow problem, I'd still like to understand why my procedure is returning "None" .. Is it mistake with my if statements ? a syntax error ?
Here is the problem:
Define a procedure, union, that takes as inputs two lists.
It should modify the first input list to be the set union of the two lists. You may assume the first list is a set, that is, it contains no repeated elements.
The result we are expecting:
a = [1,2,3]
b = [2,4,6]
union(a,b)
print a
#>>> [1,2,3,4,6]
You will note that, in my procedure, I'm using another procedure to find if a list item is in the other list. Could the problem be coming from that ?
Here is my code:
def find_element(a,b):
if b in a:
return a.index(b)
return - 1
def union(a,b):
i = 0
while i < len(b) - 1:
c = find_element(a,b[i])
if c != -1:
i = i + 1
if c == -1:
a = a.append(b[i])
i = i + 1
return a
a = [1,2,3]
b = [2,4,6]
print(union(a,b))
a = a.append(b[i])
Here, a.append(b[i]) appends b[i] to a and returns 'none' which you have assigned to 'a'.
change this to
a.append(b[i])
and you should atleast get an output.
just in case you may need it.
you code could will be easier to read if you have it like this.
but its nice to challenge yourself.
best,
def union(a, b):
for item in b:
if item not in a:
a.append(item)
return a
a = [1, 2, 3]
b = [2, 4, 6]
x = union(a, b)
print(x)

what is the meaningin python of list=[none]*list size

""" https://www.interviewcake.com/question/python/merge-sorted-arrays """
import unittest
def merge_sorted_arrays(first, second):
# setup our merged list
merged_list_size = len(first) + len(second)
merged_list = [None] * merged_list_size
What is the meaning of merged_list=[None]*merged_list_size? What does [None] stands for?
This will create a list with merged_list_size number of None elements.
Say merged_list_size was 3...
>>> merged_list=[None]*3
>>> print merged_list
[None, None, None]
The result is a list with 3 elements all of the value None
edit:
when coming across things like this that you don't understand I would always test before looking for help. I personally always open a terminal and run the python command prompt to test out little things like this.
It does create a list of size merged_list_size whose elements are None. None is a built-in constant which represents the absence of a value.
Fore more info about built-in constants: https://docs.python.org/2/library/constants.html

Weird list behavior in python

qtd_packs = 2
size_pack = 16
pasta = []
pasta.append ('packs/krun/')
pasta.append ('packs/parting2/')
for k in range(0, qtd_packs):
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in)
del samples_in[0:len(samples_in)]
print(samples)
I'm basically trying to add the samples_in inside the samples list, then delete the old samples_in list to create a new one. This will happen 2 times, as the qtd_packs =2. But in the end, what I get is two empty lists:
[[], []]
I've append'ed the samples_in inside samples BEFORE deleting it. So what happened?
Thank you
In Python, lists are passed by reference. When you append samples_in to samples, Python appends a reference to samples_in to samples. If you want to append a copy of samples_in to samples, you can do:
samples.append(samples_in[:])
This effectively creates a new list from all the items in samples_in and passes that new list into samples.append(). So now when you clear the items in samples_in, you're not clearing the items in the list that was appended to samples as well.
Also, note that samples_in[:] is equivalent to samples_in[0:len(samples_in)].
The problem is that after this:
samples.append(samples_in)
The newly-appended value in samples is not a copy of samples_in, it's the exact same value. You can see this from the interactive interpreter:
>>> samples_in = [0]
>>> samples = []
>>> samples.append(samples_in)
>>> samples[-1] is samples_in
True
>>> id(samples[-1]), id(samples_in)
(12345678, 12345678)
Using an interactive visualizer might make it even easier to see what's happening.
So, when you modify the value through one name, like this:
>>> del samples_in[0:len(samples_in)]
The same modification is visible through both names:
>>> samples[-1]
[]
Once you realize that both names refer to the same value, that should be obvious.
As a side note, del samples_in[:] would do the exact same thing as del samples_in[0:len(samples_in)], because those are already the defaults for a slice.
What if you don't want the two names to refer to the same value? Then you have to explicitly make a copy.
The copy module has functions that can make a copy of (almost) anything, but many types have a simpler way to do it. For example, samples_in[:] asks for a new list, which copies the slice from 0 to the end (again, those are the defaults). So, if you'd done this:
>>> samples.append(samples_in[:])
… you would have a new value in samples[-1]. Again, you can test that easily:
>>> samples[-1], samples_in
([0], [0])
>>> samples[-1] == samples_in
True
>>> samples[-1] is samples_in
False
>>> id(samples[-1]), id(samples_in)
23456789, 12345678
And if you change one value, that doesn't affect the other—after all, they're separate values:
>>> del samples_in[:]
>>> samples[-1], samples_in
([0], [])
However, in this case, you really don't even need to make a copy. The only reason you're having a problem is that you're trying to reuse samples_in over and over. There's no reason to do that, and if you just created a new samples_in value each time, the problem wouldn't have come up in the first place. Instead of this:
samples_in = []
for k in range(0, qtd_packs):
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in)
del samples_in[0:len(samples_in)]
Do this:
for k in range(0, qtd_packs):
samples_in = []
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in)
beetea's answer below offers the solution if you want samples to contain two lists, each of which have the strings for one of your two qtd_packs:
qtd_packs = 2
size_pack = 16
pasta = []
pasta.append ('packs/krun/')
pasta.append ('packs/parting2/')
samples = []
samples_in = []
for k in range(0, qtd_packs):
for n in range(1, size_pack+1):
samples_in.append (pasta[k]+str(n)+'.wav')
samples.append(samples_in[:])
del samples_in[0:len(samples_in)]
print(samples)
produces this output:
[['packs/krun/1.wav', 'packs/krun/2.wav', 'packs/krun/3.wav', 'packs/krun/4.wav',
'packs/krun/5.wav', 'packs/krun/6.wav', 'packs/krun/7.wav', 'packs/krun/8.wav',
'packs/krun/9.wav', 'packs/krun/10.wav', 'packs/krun/11.wav', 'packs/krun/12.wav',
'packs/krun/13.wav', 'packs/krun/14.wav', 'packs/krun/15.wav', 'packs/krun/16.wav'],
['packs/parting2/1.wav', 'packs/parting2/2.wav', 'packs/parting2/3.wav',
'packs/parting2/4.wav', 'packs/parting2/5.wav', 'packs/parting2/6.wav',
'packs/parting2/7.wav', 'packs/parting2/8.wav', 'packs/parting2/9.wav',
'packs/parting2/10.wav', 'packs/parting2/11.wav', 'packs/parting2/12.wav',
'packs/parting2/13.wav', 'packs/parting2/14.wav', 'packs/parting2/15.wav',
'packs/parting2/16.wav']]
Now, when I originally read your question, I thought you were trying to make a single list containing all the strings. In that instance, you could use
samples.extend(samples_in)
instead of
samples.append(samples_in[:])
and you would get a flat list containing only the strings.

Creating a back-up list in python

I want to create a back-up list of another list in python. Here is an example of the code.
x = [1,2,3]
y = x
x.pop(0)
print y
This however yields the result y = [2,3] when I want it to yield [1,2,3]. How would I go about making the y list independent of the x list?
A common idiom for this is y = x[:]. This makes a shallow copy of x and stores it in y.
Note that if x contains references to objects, y will also contain references to the same objects. This may or may not be what you want. If it isn't, take a look at copy.deepcopy().
Here is one way to do it:
import copy
x = [1,2,3]
y = copy.deepcopy(x)
x.pop(0)
print x
print y
from the docs here
While aix has the most parsimonious answer here, for completeness you can also do this:
y = list(x)
This will force the creation of a new list, and makes it pretty clear what you're trying to do. I would probably do it that way myself. But be aware- it doesn't make a deep copy (so all the elements are the same references).
If you want to make sure NOTHING happens to y, you can make it a tuple- which will prevent deletion and addition of elements. If you want to do that:
y = tuple(x)
As a final alternative you can do this:
y = [a for a in x]
That's the list comprehension approach to copying (and great for doing basic transforms or filtering). So really, you have a lot of options.

Categories

Resources