Using .index() function in nested lists - python

I am trying to make a program that finds a certain value in a nested list, so I wrote this code:
list = [['S', 'T', 'U', 'T'], ['O', 'P', 'Q', 'R']]
However, when I inputted
list.index('O')
It gave me an error message saying
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
list.index('O')
ValueError: 'O' is not in list
Any ideas?

Well it is really simple, 'O' is not in the list, it only contains the other lists. Here is an example:
list_you_have = [['S', 'T', 'U', 'T'], ['O', 'P', 'Q', 'R']]
print list_you_have.index(['O','P','Q','R']) #outputs 1
Now if you do it like:
print list_you_have[1].index('O') # it outputs 0 because you're pointing to
#list which acctualy contains that 'O' char.
Now a function for nested char search would be
def nested_find(list_to_search,char):
for i, o in enumerate(list_to_search):
if char in o:
print "Char %s found at list %s at index %s" % (char, i, o.index(char))
Or maybe an even simpler solution as #zondo commented would be:
def nested_find(list_to_search,char):
newlist = sum(list_to_search, [])
if char in newlist:
print "Char %s is at position %s" % (char, newlist.index(char))

You can solve your problem in one-line:
print item in reduce(lambda x, y: x + y, nestedlists)

Related

How to use "None" in list when i'm using .index() and object wight not exist in list

I want to write a function that encrypt text using caesar cipher. But I want to let non-letters characters to be the same.
I have list with alphabet and a "questions for user"
alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
direction = input("Type 'encode' to encrypt, type 'decode' to decrypt:\n").lower()
text = input("Type your message:\n").lower()
shift = int(input("Type the shift number:\n"))
This is function which should let non-letters to be in code non changed
def encrypt(text, shift):
text_encrypted = [] # blank text
for letter in text: # check every letter
indeksik = alphabet.index(letter)
if indeksik == None:
text_encrypted.append(letter)
else:
text_encrypted.append(alphabet[indeksik + shift])
But then I'm getting this error:
Tracebac k (most recent call last):
File "C:\Users\mateu\PycharmProjects\Cipher\main.py", line 25, in <module>
encrypt(text, shift)
File "C:\Users\mateu\PycharmProjects\Cipher\main.py", line 16, in encrypt
indeksik = alphabet.index(letter)
ValueError: ' ' is not in list
I know that ' ' is not in list. That's the point - how I can still append to another list these spaces and other non-alphabetical characters?
(Yes, I know that in this moment it will crash when I will shift letter "beyond z" - but I will work with this later)
index() raises a ValueError exception if the value is not in the list. You can do something like:
if letter in alphabet:
# Found the letter
else:
# Not found
The other possible solution is to handle the exception itself, but I'd probably go with the first one.
For
indeksik = alphabet.index(letter)
If letter is not found in alphabet, a ValueError exception is raised.
for letter in text: # check every letter
if letter in alphabet:
indeksik = alphabet.index(letter)
text_encrypted.append(alphabet[indeksik + shift])
else:
text_encrypted.append(letter)
If you use a string, preferably not typing (and possibly mistyping) it yourself, then you can use find and you'll get -1 instead of an error:
>>> from string import ascii_lowercase as alphabet
>>> alphabet.find('c')
2
>>> alphabet.find(' ')
-1

How do I replace a string at a index in python? [duplicate]

This question already has answers here:
Changing one character in a string
(15 answers)
Closed 1 year ago.
So I already know how to remove a index like this:
i = "hello!"
i= i[:0] + i[1:]
print(i)
'ello!'
But how do I replace it?
So maybe I wanted to now put a H where the old h was but if I do this:
i[0] ="H"
I get this error:
Traceback (most recent call last):
File "<pyshell#2>", line 1, in
i[0] ="H"
TypeError: 'str' object does not support item assignment
How do I fix this?
Strings are immutable in Python, so you can't assign like i[0] = 'H'. What you can do is convert the string to list, which is mutable, then you can assign new values at a certain index.
i = "hello!"
i_list = list(i)
i_list[0] = 'H'
i_new = ''.join(i_list)
print(i_new)
Hello!
Without creating a list you could also do:
i = "hello!"
i = "H" + i[1:]
More general:
def change_letter(string, letter, index): # note string is actually a bad name for a variable
return string[:index] + letter + string[index+1:]
s = "hello!"
s_new = change_letter(s, "H", 0)
print(s_new)
# should print "Hello!"
Also note there is a built in function .capitalize()
This is a duplicate of this post
As said there you have to make a list out of your string and change the char by selecting an item from that list and reassigning a new value and then in a loop rebuilding the string.
>>> s = list("Hello zorld")
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'z', 'o', 'r', 'l', 'd']
>>> s[6] = 'W'
>>> s
['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd']
>>> "".join(s)
'Hello World'
i = "hello!"
print(i) ## will print hello!
i = "H" + i[1:]
print(i) ## will print Hello!

Getting the index of the word 'print' in a multiline string

I am trying to find the index of all the word: 'print' in a multi line text. But there are some problems, those are:
The code returns the index same of word 'print' two time if there are two prints in a line.
It is not able to find the index of the second 'print' in the same line, but prints the index of the first 'print' two times.
My code is:
text = '''print is print as
it is the function an
print is print and not print
'''
text_list = []
for line in text.splitlines():
#'line' represents each line in the multiline string
text_list.append([])
for letter in line:
#Append the letter of each line in a list inside the the text_list
text_list[len(text_list)-1].append(letter)
for line in text_list:
for letter in line:
#check if the letter is after 'p' is 'r' and after that 'i' and then 'n' and at last 't'
if letter == "p":
num = 1
if text_list[text_list.index(line)][line.index(letter)+num] == 'r':
num += 1
if text_list[text_list.index(line)][line.index(letter)+num] == 'i':
num += 1
if text_list[text_list.index(line)][line.index(letter)+num] == 'n':
num += 1
if text_list[text_list.index(line)][line.index(letter)+num] == 't':
num += 1
print(f'index (start,end) = {text_list.index(line)}.{line.index(letter)}, {text_list.index(line)}.{line.index(letter)+num}')
when I run it prints:
index (start,end) = 0.0, 0.5 #returns the index of the first 'print' in first line
index (start,end) = 0.0, 0.5 #returns the index of the first 'print' in first line instead of the index of the second print
index (start,end) = 2.0, 2.5 #returns the index of the first 'print' in third line
index (start,end) = 2.0, 2.5 #returns the index of the first 'print' in third line instead of the index of the second print
index (start,end) = 2.0, 2.5 #returns the index of the first 'print' in third line instead of the index of the third print
you can see that in the result, the index are repeated. This is the text_list:
>>> text_list
[['p', 'r', 'i', 'n', 't', ' ', 'i', 's', ' ', 'p', 'r', 'i', 'n', 't', ' ', 'a', 's'],
['i', 't', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', ' ', 'a', 'n'],
['p', 'r', 'i', 'n', 't', ' ', 'i', 's', ' ', 'p', 'r', 'i', 'n', 't', ' ', 'a', 'n', 'd', ' ', 'n', 'o', 't', ' ', 'p', 'r', 'i', 'n', 't']]
>>>
each list inside the text_list is a line in the text. There are three lines, so there are three lists inside the text_list. How do I get the index of the second 'print' in the first line and the index of second and third 'print' in the third line? You can see that it returns only the index of first 'print' in the first and third line.
import re
text = '''print is print as
it is the function an
print is print and not print
'''
for line_number, line in enumerate(text.split('\n')):
occurrences = [m.start() for m in re.finditer('print', line)]
if occurrences:
for occurrence in occurrences:
print('Found `print` at character %d on line %d' % (occurrence, line_number + 1))
->
Found `print` at character 0 on line 1
Found `print` at character 9 on line 1
Found `print` at character 0 on line 3
Found `print` at character 9 on line 3
Found `print` at character 23 on line 3
strings already have an index method to find substring, and you can give extra arguments to find the next copy of the next copy of a given subtring
>>> text = '''print is print as
it is the function an
print is print and not print
'''
>>> text.index("print")
0
>>> text.index("print",1)
9
>>> text.index("print",10)
40
>>> text.index("print",41)
49
>>> text.index("print",50)
63
>>> text.index("print",64)
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
text.index("print",64)
ValueError: substring not found
>>>
You can use regular expressions:
import re
text = '''print is print as
it is the function an
print is print and not print
'''
for i in re.finditer("print", text):
print(i.start())
# OR AS A LIST
[i.start() for i in re.finditer("print", text)]
You were on the right track initially. You split your text into lines. The next step is to split each line into words, not letters, using the split() method. You can then easily get the index of each 'print' string in each line.
The following code prints the desired indexes as list of lists, with each inner list corresponding to a separate line:
text = '''print is print as
it is the function an
print is print and not print
'''
index_list = []
for line in text.splitlines():
index_list.append([])
for idx, word in enumerate(line.split()):
if word == 'print':
index_list[-1].append(idx)
print(index_list)
#[[0, 2], [], [0, 2, 5]]

Check if a list element exists in a string

I'd like to check if a string contains an element from a list:
l = ['S', 'R', 'D', 'W', 'V', 'Y', 'H', 'K', 'B', 'M']
s = 'YTG'
The first solution is:
for i in l:
if i in s:
print i
This seems inefficient though. I tried the following code but it gives me the last element of the list 'M' instead of 'Y':
if any(i in s for i in l):
print i
I was wondering what is the problem here?
Thanks!
any() produces True or False, and the generator expression variables are not available outside of the expression:
>>> l = ['S', 'R', 'D', 'W', 'V', 'Y', 'H', 'K', 'B', 'M']
>>> s = 'YTG'
>>> any(i in s for i in l)
True
>>> i
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'i' is not defined
Use a list comprehension to list all matching letters:
matching = [i for i in l if i in s]
if matching:
print matching
That preserves the order in l; if the order in matching doesn't matter, you could just use set intersections. I'd make l a set here:
l = set(['S', 'R', 'D', 'W', 'V', 'Y', 'H', 'K', 'B', 'M']) # Python 3 can use {...}
matching = l.intersection(s)
if matching:
print matching
By making l the set, Python can iterate over the shorter s string.
any will tell you if the condition is True or False, without giving more details.
To compute the actual common letters, just create a set and perform intersection:
l = ['S', 'R', 'D', 'W', 'V', 'Y', 'H', 'K', 'B', 'M']
s = set('YTG')
print(s.intersection(l))
that yields {'Y'}.
One liner:
set(list(s)).intersection(set(l))
{'Y'}
As per #Martijn Pieters♦ comment simply:
set(s).intersection(l) will do the trick, as shown in #Jean-François Fabre's answer

How to get all substrings in a list of characters (python)

I want to iterate over a list of characters
temp = ['h', 'e', 'l', 'l', 'o', '#', 'w', 'o', 'r', 'l', 'd']
so that I can obtain two strings, "hello" and "world"
My current way to do this is:
#temp is the name of the list
#temp2 is the starting index of the first alphabetical character found
for j in range(len(temp)):
if temp[j].isalpha() and temp[j-1] != '#':
temp2 = j
while (temp[temp2].isalpha() and temp2 < len(temp)-1:
temp2 += 1
print(temp[j:temp2+1])
j = temp2
The issue is that this prints out
['h', 'e', 'l', 'l', 'o']
['e', 'l', 'l', 'o']
['l', 'l', 'o']
['l', 'o']
['o']
etc. How can I print out only the full valid string?
Edit: I should have been more specific about what constitutes a "valid" string. A string is valid as long as all characters within it are either alphabetical or numerical. I didn't include the "isnumerical()" method within my check conditions because it isn't particularly relevant to the question.
If you want only hello and world and your words are always # seperated, you can easily do it by using join and split
>>> temp = ['h', 'e', 'l', 'l', 'o', '#', 'w', 'o', 'r', 'l', 'd']
>>> "".join(temp).split('#')
['hello', 'world']
Further more if you need to print the full valid string you need to
>>> t = "".join(temp).split('#')
>>> print(' '.join(t))
hello world
You can do it like this:
''.join(temp).split('#')
List has the method index which returns position of an element. You can use slicing to join the characters.
In [10]: temp = ['h', 'e', 'l', 'l', 'o', '#', 'w', 'o', 'r', 'l', 'd']
In [11]: pos = temp.index('#')
In [14]: ''.join(temp[:pos])
Out[14]: 'hello'
In [17]: ''.join(temp[pos+1:])
Out[17]: 'world'
An alternate, itertools-based solution:
>>> temp = ['h', 'e', 'l', 'l', 'o', '#', 'w', 'o', 'r', 'l', 'd']
>>> import itertools
>>> ["".join(str)
for isstr, str in itertools.groupby(temp, lambda c: c != '#')
if isstr]
['hello', 'world']
itertools.groupby is used to ... well ... group consecutive items depending if they are of not equal to #. The comprehension list will discard the sub-lists containing only # and join the non-# sub-lists.
The only advantage is that way, you don't have to build the full-string just to split it afterward. Probably only relevant if the string in really long.
If you just want alphas just use isalpha() replacing the # and any other non letters with a space and then split of you want a list of words:
print("".join(x if x.isalpha() else " " for x in temp).split())
If you want both words in a single string replace the # with a space and join using the conditional expression :
print("".join(x if x.isalpha() else " " for x in temp))
hello world
To do it using a loop like you own code just iterate over items and add to the output string is isalpha else add a space to the output:
out = ""
for s in temp:
if s.isalpha():
out += s
else:
out += " "
Using a loop to get a list of words:
words = []
out = ""
for s in temp:
if s.isalpha():
out += s
else:
words.append(out)
out = ""

Categories