Iterating through multidimensional lists? - python

Sorry if obvious question, I'm a beginner and my google-fu has failed me.
I am writing a tool that searches through text for alliteration. I have a multi-dimensional list: [[e,a,c,h], [w,o,r,d], [l,o,o,k,s], [l,i,k,e], [t,h,i,s]]
What I want is to iterate through the items in the main list, checking the [0] index of each item to see if it is equal to the [0] index of the FOLLOWING item.
def alit_finder(multi_level_list):
for i in multi_level_list:
if i[0] == multi_level_list[i + 1][0] and i != multi_level_list[-1]:
print i, multi_level_list[i + 1]
I'm getting a TypeError: can only concatenate list (not "int") to list.
So [i + 1] is not the right way to indicate 'the item which has an index equal to the index of i plus one'. However, [ + 1] is not working, either: that seems to return ANY two words in the list that have the same letter at word[0].
How do I refer to 'the following item' in this for statement?
ETA: Thank you all! I appreciate your time and explanations as to what exactly I was doing wrong here!

In a normal for-each loop like you have, you only get access to one element at a time:
for x in lst:
print("I can only see", x)
So you need to iterate over the indexes instead, for example:
for i in range(len(lst) - 1):
print("current =", lst[i], "next =", lst[i+1])
By the way, as a convention, it's a good idea to use variables named i to always refer to loop indexes. In your original code, part of the confusion is that you tried to use i as the list element at first, and later as an index, and it can't be both!

I think you want something like this:
def alit_finder(multi_level_list):
l=len(multi_level_list)
for i in xrange(l-1):
if multi_level_list[i][0] == multi_level_list[i + 1][0]:
print multi_level_list[i], multi_level_list[i + 1]
li=[['e','a','c','h'], ['w','o','r','d'], ['l','o','o','k','s'], ['l','i','k','e'], ['t','h','i','s']]
alit_finder(li)
Result:
['l', 'o', 'o', 'k', 's'] ['l', 'i', 'k', 'e']

You could use i as the index and x as the element of an enumerated list:
def alit_finder(multi_level_list):
for i, x in enumerate(multi_level_list):
if i == len(multi_level_list) - 1:
break # prevent index out of range error
if x[0] == multi_level_list[i + 1][0] and x != multi_level_list[-1]:
return x, multi_level_list[i + 1]
word_list = [['e','a','c','h'], ['w','o','r','d'], ['l','o','o','k','s'],
['l','i','k','e'], ['t','h','i','s']]
print alit_finder(word_list)
# (['l', 'o', 'o', 'k', 's'], ['l', 'i', 'k', 'e'])

something like this will work:
matching_indices = [i for i, (w1, w2) in enumerate(zip(multi_level_list, multi_level_list[1:])) if w1[0] == w2[0]]

Related

How to rotate a list(not 2D) 90 degree clockwise?

As a beginner in Python, I think the biggest problem I have is overcomplicating a problem when it can be done a lot simpler. I have not found a solution for a list that is not two-dimensional, hence why I chose to ask.
Here is an example of what I am trying to do:
# Before
alphabet = ["ABCDEFG",
"HIJKLMN",
"OPQRSTU"]
# After
rotated_alphabet = ["OHA",
"PIB",
"QJC",
"RKD",
"SLE",
"TMF",
"UNG"]
What I have done so far:
length_of_column = len(alphabet)
length_of_row = len(alphabet[0])
temp_list = []
x = -1
for i in range(length_of_column):
while x < length_of_row-1:
x += 1
for row in alphabet:
temp_list.append(row[x])
temp_list = temp_list[::-1]
Output
print(temp_list)
>>> ['U', 'N', 'G', 'T', 'M', 'F', 'S','L','E','R','K','D','Q','J','C','P','I','B', 'O', 'H', 'A']
I need to make the list above in the desired format.
-How would I do this?
-Is there a simpler way to do it?
You can just zip the list of strings, and it will make tuples character by character, then you'll only have to join the tuples in reverse order. Here it is in just one line:
rotated_alphabet = [''.join(list(i)[::-1]) for i in zip(*alphabet)]
A variant of #MuhammadAhmad answer will be to use reversed, as reversed works with iterables, no need to convert to a list.
alphabet = ["ABCDEFG",
"HIJKLMN",
"OPQRSTU"]
rotated = [''.join(reversed(a)) for a in zip(*alphabet)]
print(rotated)
Output
['OHA', 'PIB', 'QJC', 'RKD', 'SLE', 'TMF', 'UNG']

'Clumping' a list in python

I've been trying to 'clump' a list
I mean putting items together depending on the item inbetween, so ['d','-','g','p','q','-','a','v','i'] becomes ['d-g','p','q-a','v','i'] when 'clumped' around any '-'
Here's my attempt:
def clump(List):
box = []
for item in List:
try:
if List[List.index(item) + 1] == "-":
box.append("".join(List[List.index(item):List.index(item)+3]))
else:
box.append(item)
except:
pass
return box
However, it outputs (for the example above)
['d-g', '-', 'g', 'p', 'q-a', '-', 'a', 'v']
As I have no idea how to skip the next two items
Also, the code is a complete mess, mainly due to the try and except statement (I use it, otherwise I get an IndexError, when it reaches the last item)
How can it be fixed (or completely rewritten)?
Thanks
Here's an O(n) solution that maintains a flag determining whether or not you are currently clumping. It then manipulates the last item in the list based on this condition:
def clump(arr):
started = False
out = []
for item in arr:
if item == '-':
started = True
out[-1] += item
elif started:
out[-1] += item
started = False
else:
out.append(item)
return out
In action:
In [53]: clump(x)
Out[53]: ['d-g', 'p', 'q-a', 'v', 'i']
This solution will fail if the first item in the list is a dash, but that seems like it should be an invalid input.
Here is a solution using re.sub
>>> import re
>>> l = ['d','-','g','p','q','-','a','v','i']
>>> re.sub(':-:', '-', ':'.join(l)).split(':')
['d-g', 'p', 'q-a', 'v', 'i']
And here is another solution using itertools.zip_longest
>>> from itertools import zip_longest
>>> l = ['d','-','g','p','q','-','a','v','i']
>>> [x+y+z if y=='-' else x for x,y,z in zip_longest(l, l[1:], l[2:], fillvalue='') if '-' not in [x,z]]
['d-g', 'g', 'q-a', 'a', 'v', 'i']

How to get certain number of alphabets from a list?

I have a 26-digit list. I want to print out a list of alphabets according to the numbers. For example, I have a list(consisting of 26-numbers from input):
[0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
I did like the output to be like this:
[e,e,l,s]
'e' is on the output 2-times because on the 4-th index it is the 'e' according to the English alphabet formation and the digit on the 4-th index is 2. It's the same for 'l' since it is on the 11-th index and it's digit is 1. The same is for s. The other letters doesn't appear because it's digits are zero.
For example, I give another 26-digit input. Like this:
[1,2,2,3,4,0,3,4,4,1,3,1,4,4,1,0,0,0,0,0,4,2,3,2,2,1]
The output should be:
[a,b,b,c,c,d,d,d,e,e,e,e,g,g,g,h,h,h,h,i,i,i,i,j,k,k,k,l,m,m,m,m,n,n,n,n,o,u,u,u,u,v,v,w,w,w,x,x,y,y,z]
Is, there any possible to do this in Python 3?
You can use chr(97 + item_index) to get the respective items and then multiply by the item itself:
In [40]: [j * chr(97 + i) for i, j in enumerate(lst) if j]
Out[40]: ['ee', 'l', 's']
If you want them separate you can utilize itertools module:
In [44]: from itertools import repeat, chain
In [45]: list(chain.from_iterable(repeat(chr(97 + i), j) for i, j in enumerate(lst) if j))
Out[45]: ['e', 'e', 'l', 's']
Yes, it is definitely possible in Python 3.
Firstly, define an example list (as you did) of numbers and an empty list to store the alphabetical results.
The actual logic to link with the index is using chr(97 + index), ord("a") = 97 therefore, the reverse is chr(97) = a. First index is 0 so 97 remains as it is and as it iterates the count increases and your alphabets too.
Next, a nested for-loop to iterate over the list of numbers and then another for-loop to append the same alphabet multiple times according to the number list.
We could do this -> result.append(chr(97 + i) * my_list[i]) in the first loop itself but it wouldn't yield every alphabet separately [a,b,b,c,c,d,d,d...] rather it would look like [a,bb,cc,ddd...].
my_list = [1,2,2,3,4,0,3,4,4,1,3,1,4,4,1,0,0,0,0,0,4,2,3,2,2,1]
result = []
for i in range(len(my_list)):
if my_list[i] > 0:
for j in range(my_list[i]):
result.append(chr(97 + i))
else:
pass
print(result)
An alternative to the wonderful answer by #Kasramvd
import string
n = [0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
res = [i * c for i, c in zip(n, string.ascii_lowercase) if i]
print(res) # -> ['ee', 'l', 's']
Your second example produces:
['a', 'bb', 'cc', 'ddd', 'eeee', 'ggg', 'hhhh', 'iiii', 'j', 'kkk', 'l', 'mmmm', 'nnnn', 'o', 'uuuu', 'vv', 'www', 'xx', 'yy', 'z']
Splitting the strings ('bb' to 'b', 'b') can be done with the standard schema:
[x for y in something for x in y]
Using a slightly different approach, which gives the characters individually as in your example:
import string
a = [0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
alphabet_lookup = np.repeat(np.arange(len(a)), a)
letter_lookup = np.array(list(string.ascii_lowercase))
res = letter_lookup[alphabet_lookup]
print(res)
To get
['e' 'e' 'l' 's']

Combinations of a String

The following was a job interview question which I struggled with.
(Unnecessary switching between list and set, tested it and realised it was missing an expected output, too many steps).
If possible, looking for the proper answer or maybe a guide on how I should have tackled the problem. Thank you.
Question: Give a String, find all possible combinations from it (Front and Reverse).
Print all combinations and total count of combinations. Order doesn't matter.
Example s = 'polo'
Front Answer = 'p', 'po', 'pol', 'polo', 'ol',
'olo', 'lo', 'o', 'l'.
Reverse Answer: 'o', 'ol', 'olo', 'olop',
'lop', 'op', 'p', 'l'.
My answer:
count = 0
count2 = -1
length = len(s)
my_list = []
for i in s:
temp = s[count:]
temp2 = s[:count2]
my_list.append(i)
my_list.append(temp)
my_list.append(temp2)
count += 1
count2 -= 1
my_set = set(my_list)
for f in my_set:
print(f)
print(len(my_set)) # Answer for front
new_list = []
for f in my_set:
new_list.append(f[::-1])
print('Reverse Result:')
for f in new_list:
print(f)
print(len(new_list)) # Answer for reverse
You can do this with two nested for-loops. One will loop through the start indexes and the nested one loops through the end indexes (starting from the start + 1 going to the length of s +1 to reach the very end).
With these two indexes (start and end), we can use string slicing to append that combination to the list forward. This gives you all the combinations as you see below.
To get the reversed ones, you could do a for-loop as you have done reversing the order of the forward ones, but to save the space, in the code below, we just append the same index but sliced from the reversed s (olop).
s = "polo"
forward = []
backward = []
for start in range(len(s)):
for end in range(start+1, len(s)+1):
forward.append(s[start:end])
backward.append(s[::-1][start:end])
print(forward)
print(backward)
print(len(forward) + len(backward))
which outputs:
['p', 'po', 'pol', 'polo', 'o', 'ol', 'olo', 'l', 'lo', 'o']
['o', 'ol', 'olo', 'olop', 'l', 'lo', 'lop', 'o', 'op', 'p']
20
If you really wanted to make the code clean and short, you could do the same thing in a list-comprehension. The logic remains the same, but we just compress it down to 1 line:
s = "polo"
forward = [s[start:end] for start in range(len(s)) for end in range(start+1, len(s)+1)]
backward = [c[::-1] for c in forward]
print(forward)
print(backward)
print(len(forward) + len(backward))
which gives the same output as before.
Hope this helps!
Try this:
string = "polo"
x = [string[i:j] for i in range(len(string)) for j in range(len(string),0,-1) if j > i ]
x.sort()
print("Forward:",x[::-1])
print("Reverse:",x[::])

Compare lists to find common elements in python [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Python - Intersection of two lists
i'm trying to compare two lists in order to find the number of elements they have in common.
The main problem I'm having is when either list contains repeated elements, for example
A = [1,1,1,1] and
B = [1,1,2,3]
using the code
n = 0
for x in A:
if x in B:
n += 1
print n
gives me the output that n = 4, as technically all elements of A are in B
I'd like to get the output that n = 2, preferably without using sets, Is there anyway I can adapt my code, or a new way of thinking about the problem to achieve this?
Thanks
It's not entirely clear what your specification is, but if you want the number of elements in A that appear in B, without regard to order, but with regard to multiplicity, use collections.Counter:
>>> from collections import Counter
>>> A = [1,1,1,1]
>>> B = [1,1,2,3]
>>> C = Counter(A) & Counter(B)
>>> sum(C.itervalues())
2
>>> list(C.elements())
[1, 1]
Here is an efficient (O(n logn)) way to do it without using sets:
def count_common(a, b):
ret = 0
a = sorted(a)
b = sorted(b)
i = j = 0
while i < len(a) and j < len(b):
c = cmp(a[i], b[j])
if c == 0:
ret += 1
if c <= 0:
i += 1
if c >= 0:
j += 1
return ret
print count_common([1,1,1,1], [1,1,2,3])
If your lists are always sorted, as they are in your example, you can drop the two sorted() calls. This would give an O(n) algorithm.
Here's an entirely different way of thinking about the problem.
Imagine I've got two words, "hello" and "world". To find the common elements, I could iterate through "hello", giving me ['h', 'e', 'l', 'l', 'o']. For each element in the list, I'm going to remove it from the second list(word).
Is 'h' in ['w', 'o', 'r', 'l', 'd']? No.
Is 'e' in ['w', 'o', 'r', 'l', 'd']? No.
Is 'l' in ['w', 'o', 'r', 'l', 'd']? Yes!
Remove it from "world", giving me ['w', 'o', 'r', 'd'].
is 'l' in ['w', 'o', 'r', 'd']? No.
Is 'o' in ['w', 'o', 'r', 'd']?
Yes! Remove it ['w', 'o', 'r', 'd'], giving me ['w', 'r', 'd']
Compare the length of the original object (make sure you've kept a copy around) to the newly generated object and you will see a difference of 2, indicating 2 common letters.
So you want the program to check whether only elements at the same indices in the two lists are equal? That would be pretty simple: Just iterate over the length of the two arrays (which I presume, are supposed to be of the same length), say using a variable i, and compare each by the A.index(i) and B.index(i) functions.
If you'd like, I could post the code.
If this is not what you want to do, please do make your problem clearer.

Categories

Resources