Python3 TypeError: list indices must be integers or slices, not str - string

i have the task to get the String 'AAAABBBCCDAABBB' into a list like this: ['A','B','C','D','A','B']
I am working on this for 2 hours now, and i can't get the solution. This is my code so far:
list = []
string = 'AAAABBBCCDAABBB'
i = 1
for i in string:
list.append(i)
print(list)
for element in list:
if list[element] == list[element-1]:
list.remove(list[element])
print(list)
I am a newbie to programming, and the error "TypeError: list indices must be integers or slices, not str" always shows up...
I already changed the comparison
if list[element] == list[element-1]
to
if list[element] is list[element-1]
But the error stays the same. I already googled a few times, but there were always lists which didn't need the string-format, but i need it (am i right?).
Thank you for helping!
NoAbL

First of all don't name your variables after built in python statements or data structures like list, tuple or even the name of a module you import, this also applies to files. for example naming your file socket.py and importing the socket module is definitely going to lead to an error (I'll leave you to try that out by yourself)
in your code element is a string, indexes of an iterable must be numbers not strings, so you can tell python
give me the item at position 2.
but right now you're trying to say give me the item at position A and that's not even valid in English, talk-less of a programming language.
you should use the enumerate function if you want to get indexes of an iterable as you loop through it or you could just do
for i in range(len(list))
and loop through the range of the length of the list, you don't really need the elements anyway.
Here is a simpler approach to what you want to do
s = string = 'AAAABBBCCDAABBB'
ls = []
for i in s:
if ls:
if i != ls[-1]:
ls.append(i)
else:
ls.append(i)
print(ls)

It is a different approach, but your problem can be solved using itertools.groupby as follows:
from itertools import groupby
string = 'AAAABBBCCDAABBB'
answer = [group[0] for group in groupby(string)]
print(answer)
Output
['A', 'B', 'C', 'D', 'A', 'B']
According to the documentation, groupby:
Make an iterator that returns consecutive keys and groups from the iterable
In my example we use a list comprehension to iterate over the consecutive keys and groups, and use the index 0 to extract just the key.

You can try the following code:
list = []
string = 'AAAABBBCCDAABBB'
# remove the duplicate character before append to list
prev = ''
for char in string:
if char == prev:
pass
else:
list.append(char)
prev = char
print(list)
Output:
['A', 'B', 'C', 'D', 'A', 'B']

In your loop, element is the string. You want to have the index.
Try for i, element in enumerate(list).
EDIT: i will now be the index of the element you're currently iterating through.

Related

How to create a chaining or cyclic sequence with a list in Python, so that after the last index of a list we can start from first index again

I have an alphabets list:
alpha_list = ['a', 'b', 'c', 'd', 'e']
For a given alphabet(considering it will always be present in alpha_list) I want to get an alphabet whose index is garter by a given number, consider below function for example:
def get_replacing_letter(alphabet, number):
index = alpha_list.index(alphabet)
return alpha_list[index + number]
get_replacing_letter('a', 2) will give me 'c'
what I want is get_replacing_letter('d', 2) should give 'a'
similarly get_replacing_letter('e', 2) should give 'b'
So the alph_list should work in a chaining sequence or cyclic manner. I am wondering how to achieve this in Python?
You can make new index take the modulo of the length of the list:
return alpha_list[(index + number) % len(alpha_list)]
At the moment I achieved it by extending the alpha_list with itself:
alpha_list.extend(alpha_list)
This way as index method gives first index of occurance, I could manage to get it working.
However I am wondering if there is any better way to achieve this.

Creating a dictionary from list of lists using only one for loop

I came across this question in a test. There are two parts to this question:
Part i:
Given a list of flavors, eg. ['A','A','A','A','B','B','B','B','B','C','C','C','C'], write a function that returns a dictionary of the number of each flavor respectively.
My solution:
flavors = ['A','A','A','A','B','B','B','B','B','C','C','C','C']
def count_flavors(l):
dict_flavors={}
for i in l:
dict_flavors[i] = l.count(i)
return dict_flavors
print(count_flavors(flavors))
Part ii:
Using not more than ONE for loop write a function that accepts a list of lists of flavors eg. [['A', 'A', 'B', 'B', 'B', 'C', 'C'], ['A', 'A', 'B', 'B', 'B', 'B', 'C'], ['A', 'B', 'C', 'C']] and returns a dictionary for the total number of each flavor. You must include the function that you defined in part one in this solution.
(To clarify, essentially there should only be two for loops; one from part one and one from part two)
So far my solution is the following:
batches = [['A','A','A','A','B','B','B','B','B','C','C','C','C'], ['A', 'A', 'B', 'B' ,'B','B','C'], ['A','B','C','C']]
def batch_count(b):
batch_dict = []
result = {}
for j in b:
batch_dict.append(count_flavors(j))
print(batch_dict)
for i in batch_dict:
for k in i.keys():
result[k] = result.get(k,0) + i[k]
return result
print('batch count 1:' + str(batch_count(batches)))
I am struggling to find a solution that only uses one for loop for this part. I am aware that there are modules that exist for this sort of thing like collections.Counter(). Is a naive solution that does not include any modules possible for this problem?
Thanks!
Here is the best naive solution which I can think of in order to achieve what you want
Benefits of using the solution
No need to create extra variable like batch_dict = [], which takes unnecessary space in your system
No need to carry out multiple computations using different methods, like you did above using count_flavors()
Straight forward and easy to understand
FINAL SOLUTION
batches = [['A','A','A','A','B','B','B','B','B','C','C','C','C'], ['A', 'A', 'B', 'B' ,'B','B','C'], ['A','B','C','C']]
def batch_count(b):
result = {} # for storing final count results
# two loops are required to get into the arrays of array, not other option is there
for items in b:
# Getting the nested array item here
for item in items:
# final computation, if the item is there in the result dict, then increment
# else simply assign 1 to the item as a key which eventually gives you the total number
# of counts of each item throughout the batches array items
if item in result:
result[item] += 1
else:
result[item] = 1
return result
print('batch count 1:' + str(batch_count(batches)))
# OUTPUT
# >>> batch count 1:{'A': 7, 'C': 7, 'B': 10}
Feel free to test this out for some other batches too, and let me know. This is by far the naive solution which is possible to give out what you want to achieve. Keep learning :)
ANOTHER SOLUTION [MAKING USE OF FIRST METHOD COUNT_FLAVORS]
Hey, if you really want to use the first method, then there is a work around, but you need to compromise with one thing now, that is Counter has to be imported, but I assure you, it will be as simple as that, and will give you straight forward answer
Your count_flavors works fine, so we take the count_falvors() as is.
We will be making changes to the batch_count method now
FINAL SOLUTION
from collections import Counter
# Taking your method as is, to get the dictionary which counts
# the items occurence from your array
def count_flavors(l):
dict_flavors={}
for i in l:
dict_flavors[i] = l.count(i)
return dict_flavors
# This method will do your stuffs
def batch_count(b):
result = {} #this will be used to return the final result
# now just one loop, since we will passing the array
# to our method for computation count_flavors()
for items in b: # this will give out single array
'''
now we will call your count_flavor method
we will use Counter() to merge the dictionary data
coming from the count_flavor and then add it to the result
Counter() keep track of same item, if present in multiple
dict, ADDS +1 to the same item, doesn't duplicate value
Hence counter required
'''
if len(result) != 0:
# if the result is not empty, then result = result + data
result += Counter(count_flavors(items)) # no more extra for loop
else:
# else first fill the data by assigning it
result = Counter(count_flavors(items))
# this will give out the output in {}
# else the output will come in Counter({}) format
return dict(result)
# our test array of arrays
batches = [['A','A','A','A','B','B','B','B','B','C','C','C','C'], ['A', 'A', 'B', 'B' ,'B','B','C'], ['A','B','C','C']]
print('batch count 1:' + str(batch_count(batches)))
# OUTPUT
# >>> batch count 1:{'A': 7, 'B': 10, 'C': 7}
In this way you achieve the output with the usage of your count_flavors() method too, that too with no multiple loops in the batch_count(). Hope that will give you more clarity :). If this works out for you, you may accept the answer, for the the people who will come looking for answer to this question :)
The first function can become much faster by modifying your approach in this way:
def count_flavors(lst):
dict_flavors = {}
for item in lst:
if item in dict_flavors:
dict_flavors[item] += 1
else:
dict_flavors[item] = 1
return dict_flavors
You could also use Counter to simplify your code:
from collections import Counter
def count_flavors(lst):
return dict(Counter(lst))
The second function can use itertools.chain:
from collections import Counter
from itertools import chain
def batch_count(b):
return dict(Counter(chain(*b)))

TypeError: list indices must be integers or slices, not str. While selecting item from loop for

I´ve been trying for a while to select an item from a list with the variable of the for loop. But I keep getting this error:
TypeError: list indices must be integers or slices, not str
The issue dissapears when I change the i for a number, but that's not what I want to do. I´ve been looking for similar issues but couldn't manage to get it working. Advise please.
I want this to result as: ['p1', 'q1', 'p2', 'q2', 'p3', 'q3', 'p4', 'q4', 'p5', 'q5']
listcont=[]
cont=0
while cont<=5:
for i in list:
listcont.append(list[i]+str(cont))
cont+=1
return listcont
n=5
list=['q','p']
print(concat(list,n))´´´
First, when you write for i in list you're already iterating over the elements of the list, not the indices. So you can use the item directly:
listcont.append(i + str(cont))
Second, you shouldn't name things list since it shadows the built-in of that name and will cause all kinds of trouble.
Third, the while loop would be better written as a for with a range
n = 5
my_list = ['q', 'p']
listcont = []
for counter in range(1, n+1):
for item in my_list:
listcont.append(item + str(counter))
Finally, you can simplify all of this into a list comprehension and make it look neater with an f-string:
def make_list(my_list, limit):
return [f'{item}{counter}' for counter in range(1, limit+1) for item in my_list]
make_list(['p', 'q'], 5)
When you use for loop, you must know that if you are using for i in list it means that i here is the element of the list, and the loop will traverse each element of the list.
While, what you want to do is for i in range(len(list)), this will traverse the list with i as a number which can gain a value, less than or equal to len(list) - 1.
You can learn this very basic thing about for loop here and hold yourself back from asking such questions.
Hope it helps, thanks.
You have a variable called list which is a bad idea because list is the type of a list in Python. But this isn't the issue. I'm guessing the function you have there, which is missing the declaration, is the function def concat(list, n), and you intended to write while cont <= n.
If all this is the case, when you do
for i in list:
i is going to be members of the list, so 'q', then 'p'. In this case list['p'] doesn't make any sense.
To get the output you're going for I would do (to be easy to read):
def concat(lst, n):
result = []
for i in range(n):
for v in lst:
result.append('{}{}'.format(v, i+1))
return result
You could do the whole thing in one line with:
['{}{}'.format(value, count + 1) for count in range(n) for value in lst]

Why is sorted() not sorting my list of strings?

Problem:
So I was trying to alphabetically sort my list of strings maybe I overlooked something very minor. I have tried both .sort and sorted() but maybe I didn't do it correctly?
Here is my Code:
words = input("Words: ")
list1 = []
list1.append(words.split())
print(sorted(list1))
Expected output-
Input: "a b d c"
Output: ['a', 'b', 'c', 'd']
Current output-
Input: "a b d c"
Output: [['a', 'b', 'd', 'c']]
Your code is not working because you are trying to sort a list inside a list.
When you call words.split() it returns a list. So when you do list1.append(words.split()) it is appending a list into list1.
You should do this:
words = input("Words: ")
list1 = words.split()
print(sorted(list1))
You can try a simple method as follows:
list1 = [i for i in input('Words: ').split(' ')]
print(sorted(list1))
I've tested it. And it is working
Without deviating from your current effort, the only modification you need to do to fix your code is :
words = input("Words: ")
list1 = []
list1.append(words.split())
print(sorted(list1[0]))
Explanation of what you were doing wrong:
The root cause of your confusion is append() .According to python docs,append() takes exactly one argument.
So when you do this,
words.split()
You are trying to append more than 1 element into the list1 and when you append() something more than 1 in a list, it appends as a nested list (i.e a list inside another list.)
To support my explanation you can see that your code fixed by a simple [0]
print(sorted(list1[0]))
That is because your input is stored as a list of list, AND it is stored in the first index (Point to note - 1st index in a python list is 0, hence the usage of list1[0])
Please let me know if I could have explained it in a more simpler way or if you have any other confusions that aid from the above explanation.

How to Sort Alphabets

Input : abcdABCD
Output : AaBbCcDd
ms=[]
n = input()
for i in n:
ms.append(i)
ms.sort()
print(ms)
It gives me ABCDabcd.
How to sort this in python?
Without having to import anything, you could probably do something like this:
arr = "abcdeABCDE"
temp = sorted(arr, key = lambda i: (i.lower(), i))
result = "".join(temp)
print(result) # AaBbCcDdEe
The key will take in each element of arr and sort it first by lower-casing it, then if it ties, it will sort it based on its original value. It will group all similar letters together (A with a, B with b) and then put the capital first.
Use a sorting key:
ms = "abcdABCD"
sorted_ms = sorted(ms, key=lambda letter:(letter.upper(), letter.islower()))
# sorted_ms = ['A', 'a', 'B', 'b', 'C', 'c', 'D', 'd']
sorted_str = ''.join(sorted_ms)
# sorted_str = 'AaBbCcDd'
Why this works:
You can specify the criteria by which to sort by using the key argument in the sorted function, or the list.sort() method - this expects a function or lambda that takes the element in question, and outputs a new criteria by which to sort it. If that "new criteria" is a tuple, then the first element takes precedence - if it's equal, then the second argument, and so on.
So, the lambda I provided here returns a 2-tuple:
(letter.upper(), letter.islower())
letter.upper() as the first element here means that the strings are going to be sorted lexigraphically, but case-insensitively (as it will sort them as if they were all uppercase). Then, I use letter.islower() as the second argument, which is True if the letter was lowercase and False otherwise. When sorting, False comes before True - which means that if you give a capital letter and a lowercase letter, the capital letter will come first.
Try this:
>>>s='abcdABCD'
>>>''.join(sorted(s,key=lambda x:x.lower()))
'aAbBcCdD'

Resources