python indexing complex list - list

I learned C over last summer, using K&R 2nd ed. book on C from 1989. I decided then to take CS50, and am now learning python3 for the first time.
I also decided to take a tutorial on python3, online at http://www.python-course.eu/python3_sequential_data_types.php,. I'm having some trouble understanding pythons indexing for deeply nested lists.
I've spent a while searching before posting, but did not see the answer. The examples i found online are of this kind:
>>> t = [[100, 'str_1'], [200, 'str_2'], [300, 'str_3']]
which i do understand. The indexing is the same as C 2d char array.
What is confusing me is this:
place= ["High up", ["further down", ["and down", ["deep down", "the answer", 42]]]]
>>> place[0]
'High up'
>>> place[1]
['further down', ['and down', ['deep down', 'the answer', 42]]]
>>> place[1][1]
['and down', ['deep down', 'the answer', 42]]
>>> place[1][1][1]
['deep down', 'the answer', 42]
>>> place[1][1][1][0]
'deep down'
>>> place[1][1][1][0][3]
'p'
I thought i got it, just keep going over one, to get to the next list, but then i found this.
>>> complex_list = [["a",["b",["c","x"]]],42]
complex_list[0] #note: index 0 is the entire left, while above it's not.*
['a', ['b', ['c', 'x']]]
>>> complex_list[0][1]
['b', ['c', 'x']]
>>> complex_list[0][1][1][0]
'c'
The two list look almost the same to me, except that complex_list has two braces on the left.
Can someone explain the rule to me, I don't see why place[0] is only the first item in the list, while complex_list[0] is the entire list except for the number 42? How does that extra brace change the indexing?

You can think about it as each list within a list being a separate item. Whatever is in the list is irrelevant until you access it.
For your example:
place = ["high up", [...]]
place[0] is "high up" because the first item in place is that string.
complex_list = [[...], 42]
complex_list[0] is the whole list except 42 because the list is the first item.

Hope this helps you understand nesting a bit better:
a = ['this element is in outer list', #index No. [0]
['this is inner list', #index No. [1] to get whole list and index No. [1][0] to get 1st element
['this is inner list within inner list', #index No. [1][1] will get you list and No. [1][1][0] will get 1st element
['this is inner list within inner list that is within inner list']]], #index No. [1][1][1]
'this element is in outer list', #index No. [2]
['this is inner list'], #index No. [3] if you want that list and index No. [3][0] to get string
'this element is in outer list'] #index No. [4]
print a[0] #this element is in outer list
print a[1] #['this is inner list', ['this is inner list within inner list', ['this is inner list within inner list that is within inner list']]]
print a[1][0] #this is inner list
print a[1][1] #['this is inner list within inner list', ['this is inner list within inner list that is within inner list']]
print a[1][1][0] #this is inner list within inner list
print a[1][1][1] #['this is inner list within inner list that is within inner list']
print a[2] #this element is in outer list
print a[3] #['this is inner list']
print a[3][0] #this is inner list
print a[4] #this element is in outer list
Furthermore, you can access strings as if they are lists therefore if you have:
b = 'Example'
print b[0] #this will print E
print b[1] #this will print x

I hope this helps you.
The two braces at the beginning of complex_list imply that what ever the length of complex_list it's first item complex_list[0] is another list, where as in place your first item place[0] is just a string 'High up'.
Now, you should know a string is a set of characters which could also be accessed using indexing, so you could also access different elements in item place[0] as follows:
print(place[0][0]) # first element in string of characters 'High up'
# H
print(place[0][1]) # second element in string of characters 'High up'
# i
print(place[0][5]) # sixth element in string of characters 'High up'
# u
All the elements printed here are characters in the string found in item one of the list place.
In the case of complex_list, the first item complex_list[0] is a list and so can further be accessed by indexing while the second item complex_list[1] is an integer which cannot be indexed further

Related

Python3: Checking if a key word within a dictionary matches any part of a string

I'm having trouble converting my working code from lists to dictionaries. The basics of the code checks a file name for any keywords within the list.
But I'm having a tough time understanding dictionaries to convert it. I am trying to pull the name of each key and compare it to the file name like I did with lists and tuples. Here is a mock version of what i was doing.
fname = "../crazyfdsfd/fds/ss/rabbit.txt"
hollow = "SFV"
blank = "2008"
empty = "bender"
# things is list
things = ["sheep", "goat", "rabbit"]
# other is tuple
other = ("sheep", "goat", "rabbit")
#stuff is dictionary
stuff = {"sheep": 2, "goat": 5, "rabbit": 6}
try:
print(type(things), "things")
for i in things:
if i in fname:
hollow = str(i)
print(hollow)
if hollow == things[2]:
print("PERFECT")
except:
print("c-c-c-combo breaker")
print("\n \n")
try:
print(type(other), "other")
for i in other:
if i in fname:
blank = str(i)
print(blank)
if blank == other[2]:
print("Yes. You. Can.")
except:
print("THANKS OBAMA")
print("\n \n")
try:
print(type(stuff), "stuff")
for i in stuff: # problem loop
if i in fname:
empty = str(i)
print(empty)
if empty == stuff[2]: # problem line
print("Shut up and take my money!")
except:
print("CURSE YOU ZOIDBERG!")
I am able to get a full run though the first two examples, but I cannot get the dictionary to run without its exception. The loop is not converting empty into stuff[2]'s value. Leaving money regrettably in fry's pocket. Let me know if my example isn't clear enough for what I am asking. The dictionary is just short cutting counting lists and adding files to other variables.
A dictionary is an unordered collection that maps keys to values. If you define stuff to be:
stuff = {"sheep": 2, "goat": 5, "rabbit": 6}
You can refer to its elements with:
stuff['sheep'], stuff['goat'], stuff['rabbit']
stuff[2] will result in a KeyError, because the key 2 is not found in your dictionary. You can't compare a string with the last or 3rd value of a dictionary, because the dictionary is not stored in an ordered sequence (the internal ordering is based on hashing). Use a list or tuple for an ordered sequence - if you need to compare to the last item.
If you want to traverse a dictionary, you can use this as a template:
for k, v in stuff.items():
if k == 'rabbit':
# do something - k will be 'rabbit' and v will be 6
If you want to check to check the keys in a dictionary to see if they match part of a string:
for k in stuff.keys():
if k in fname:
print('found', k)
Some other notes:
The KeyError would be much easier to notice... if you took out your try/except blocks. Hiding python errors from end-users can be useful. Hiding that information from YOU is a bad idea - especially when you're debugging an initial pass at code.
You can compare to the last item in a list or tuple with:
if hollow == things[-1]:
if that is what you're trying to do.
In your last loop: empty == str(i) needs to be empty = str(i).

How to split a list in python based on index

I have a list which has number and description alternatively. I would like to split it into 2 based on the index so that I can separate number and description. I tried this but it doesn't work-
list to be split based on index is named list2
for i in range (0,len(list2),1):
if (i%2==0):
new_list1=list() #list only with values
dummy=list2[i]
i1=0
new_list1[i1]=dummy
i1=i1+2
else:
new_lisy2=list() #list with description only
dummy2=list2[i]
i2=1
new_list2[i2]=dummy2
i2=i2+2
This should work but sadly it doesn't and when I debug it skips going to else statement. Please help.
I have a list which has number and description alternatively
Why not just use slicing:
original_list = [1,'one',2,'two',3,'three']
numbers_list = a[::2] # start at index[0], continue through list, get every 2nd element
>>> print numbers_list
[1, 2, 3]
strings_list = a[1::2] # start at index[1], continue through list, get every 2nd element
>>> print strings_list
['one', 'two', 'three']

List output formatting in a variable

I made a Email Bot that crawls Craigslist and emails me when an item meets my queries. I am at the final stage and have everything working but my email format.
What I have is a loop that appends Craigslist Listings to a list. Outside my loop I add the List to my email Def as an argument.
Example of what I need:
list = ['item1', 'item2', 'item3']
print list
['item1', 'item2', 'item3'] # I don't want it on a single line
for i in list:
print i
item1
item2
item3
#I want a variable with the single line item format.
I want the single line format placed into a Variable rather than as the list. My list could be 1 item or 20, depends on what has been posted on Craigslist.
Any help would be great.
With str.join you can join a list by the string given:
"\n".join(my_list)
If you need more fancy formatting than a string per line you should look at a combination of join and str.format
P.S.: By the way, don't shadow the "list" builtin, that's bad practice. It will lead to errors whenever you want to use the builtin.
Not entirely clear what you are asking. As I understand the question, you want to print the list items on different lines, but in the same style as used when printing the list in one line.
The __str__ method of a container class usually uses the __repr__ method of the contained objects, so if you want to print the items on several lines in the same style as when you print it in one line, use the repr function to get the result of __repr__.
>>> lst = ['item1', 'item2', 'item3']
>>> for i in lst:
... print repr(i)
...
'item1'
'item2'
'item3'

Sorting a list in python with items that begin with specified letters

If I have a list:
list = ('john', 'adam', 'tom', 'danny')
and I want a sorted output with the items where the first letter is between 'a' and 'h', like:
('adam', 'danny', 'john')
which sorting function in Python do I need to complete this task?
This is the code i tried:
l = list()
while True:
s = raw_input("Enter a username: ")
l.append(s)
print sorted(l)
You need 2 distinct things: a list with just the elements that begin with an acceptable letter, and then the sorted version of that list. The former can be done with a list comprehension (although, as #jonrsharpe points out, you look like you want tuples, so you meat need to convert to a list & the convert the result back).

how to check if previous element is similar to next elemnt in python

I have a text file like:
abc
abc
abc
def
def
def
...
...
...
...
Now I would like o create a list
list1=['abc','abc','abc']
list2=['def','def','def']
....
....
....
I would like to know how to check if next element is similar to previous element in a python for loop.
You can create a list comprehension and check if the ith element is equal to the ith-1 element in your list.
[ list1[i]==list1[i-1] for i in range(len(list1)) ]
>>> list1=['abc','abc','abc']
>>> [ list1[i]==list1[i-1] for i in range(len(list1)) ]
[True, True, True]
>>> list1=['abc','abc','abd']
>>> [ list1[i]==list1[i-1] for i in range(len(list1)) ]
[False, True, False]
This can be written within a for loop as well:
aux_list = []
for i in range(len(list1)):
aux_list.append(list1[i]==list1[i-1])
Check this post:
http://www.pythonforbeginners.com/lists/list-comprehensions-in-python/
for i in range(1,len(list)):
if(list[i] == list[i-1]):
#Over here list[i] is equal to the previous element i.e list[i-1]
file = open('workfile', 'r') # open the file
splitStr = file.read().split()
# will look like splitStr = ['abc', 'abc', 'abc', 'def', ....]
I think the best way to progress from here would be to use a dictionary
words = {}
for eachStr in splitStr:
if (words.has_key(eachStr)): # we have already found this word
words[eachStr] = words.get(eachStr) + 1 # increment the count (key) value
else: # we have not found this word yet
words[eachStr] = 1 # initialize the new key-value set
This will create a dictionary so the result would look like
print words.items()
[('abc', 3), ('def', 3)]
This way you store all of the information you want. I proposed this solution because its rather messy to create an unknown number of lists to accommodate what you want to do, but it is easy and memory efficient to store the data in a dictionary from which you can create a list if need be. Furthermore, using dictionaries and sets allow you to have a single copy of each string (in this case).
If you absolutely need new lists let me know and I will try to help you figure it out