Alternative ways for iterator chaining in List Comprehension? - python

I want to chain two or more different iterators together in list comprehension.
Assume I want to combine uppercase and lowercase letters into a list. The original way I though was like this,
lst1 = [chr(i) for i in range(97,123)]
lst2 = [chr(i) for i in range(65,91)]
lst = lst1+lst2
However I thought there must be some other ways to do this nicely in a single line, and then I used this with itertools module,
lst = [chr(i) for i in itertools.chain(range(97,123), range(65,91))]
In the end I also thought of tuple unpacking,
lst = [chr(i) for i in (*range(97,123), *range(65,91))]
Itertools was slower compared with two other methods (tuple unpacking was the fastest one)
For example, characters in the first range and the second range make the list of
>>> lst1
['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']
>>> lst2
['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']
I want them merged with only 1 iterator, not two separate ones. The example of the merged list, where 2 different ranges of values are used is given below,
>>> lst
['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', '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']
Is there any way to improve this or change the design?

You've found the correct solution(s).
Note: itertools.chain may be trivially slower, but it has the advantage of being (effectively) zero memory overhead, and I'd recommend it in general. range is already (effectively) zero memory overhead, so using it with chain means no meaningful memory overhead at all, while using unpacking to a tuple involves realizing both ranges as a tuple for no real reason. If the sizes never increase, then whatever, but if the inputs might be variable length, chain is safer than realizing an unbounded iterable in memory.
Of course, for your specific case, the obvious solution (that's significantly more readable) is:
import string
lst = list(string.ascii_letters)

This is probably not as neat as the list pulled from the package string BUT it does solve your question by creating a single iterable by taking the union of two sets and should be quite efficient as well.
>>> [chr(i) for i in set(range(97,123)).union(range(65,91))]
['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', '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']

Related

How to prepare batches of data from a list of values? [duplicate]

This question already has answers here:
Iterate an iterator by chunks (of n) in Python?
(14 answers)
Closed 2 years ago.
Here's a list that I have,
data = (i for i in list("abcdefghijklmnopqrstuvwxyzabcedefghijklmnopqrstuvwxyz"))
Here data is a generator and I want to iterate over it and prepared batches of 12 equal datapoints, if it is less than 12 in last batch I need it too, but below code is not working,
subsets = []
subset = []
for en, i in enumerate(data):
if en % 12 == 0 and en > 0:
subsets.append(subset)
subset = []
else:
subset.append(i)
print(subsets)
[['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'],
['n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x'],
['z', 'a', 'b', 'c', 'e', 'd', 'e', 'f', 'g', 'h', 'i'],
['k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u']]
But my code is not working properly because the first nested list has 12 values but rest of it have 11 values and it missed out last few values which are less than 12 in the last batch
Expected Output:
[['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', 'a', 'b', 'c', 'e', 'd', 'e', 'f', 'g', 'h', 'i'],
['j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u'],
['v', 'w', 'x', 'y', 'z']]
Two changes, you need to start iterating from 1 and append in the sublist before emptying it:
data = (i for i in list("abcdefghijklmnopqrstuvwxyzabcedefghijklmnopqrstuvwxyz"))
subsets = []
subset = []
# start counting from index '1'
for en, i in enumerate(data, 1):
if en % 12 == 0 and en > 0:
# append the current element before emptying 'subset'
subset.append(i)
subsets.append(subset)
subset = []
else:
subset.append(i)
# append the left-over sublist/subset to your main list as well
subsets.append(subset)
for i in subsets:
print(i)
gives
['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', 'a', 'b', 'c', 'e', 'd', 'e', 'f', 'g', 'h', 'i']
['j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u']
['v', 'w', 'x', 'y', 'z']
Alternative solution is using buit-in itertools.islice. You can check to see which approach is faster or more convenient. Kr.
import itertools
def gen_sublist(your_iter, size):
while True:
part = tuple(itertools.islice(your_iter, size))
if not part:
break
yield part
data = (i for i in list("abcdefghijklmnopqrstuvwxyzabcedefghijklmnopqrstuvwxyz"))
for c in gen_sublist(data, size=12):
print(c)
which returns:
('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', 'a', 'b', 'c', 'e', 'd', 'e', 'f', 'g', 'h', 'i')
('j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u')
('v', 'w', 'x', 'y', 'z')
A different approach which does not use modulo or enumeration (just another option since other answers already correct your approach):
In [1]: subsets = []
In [2]: data = (i for i in list("abcdefghijklmnopqrstuvwxyzabcedefghijklmnopqrstuvwxyz"))
In [3]:
...: while True:
...: try:
...: x = []
...: for i in range(12):
...: x.append(next(data))
...: subsets.append(x)
...: except: # Catch StopIteration Exception when generator runs out of values
...: subsets.append(x)
...: break
...:
Outputs:
In [4]: subsets
Out[4]:
[['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', 'a', 'b', 'c', 'e', 'd', 'e', 'f', 'g', 'h', 'i'],
['j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u'],
['v', 'w', 'x', 'y', 'z']]

How to add repeats of the same element to list by comparing index in Python?

I'm attempting to do work with lists in Python and there is a certain part I've been stuck on:
Objective: Iterate through a master list (alphabet) of x amount of elements, and compare whether the index of said element is a factor of 7. If so, append this element to a new list (final). It seems very simple, and here is the code I've written so far:
def test():
alphabet = ['a', 'a', 'b' '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', 'li', 'a']
final = []
for letter in alphabet:
if (alphabet.index(letter) % 7 == 0):
final.append(letter)
print final
The output I am getting: ['a', 'a', 'g', 'n', 'u', 'a']
The output I am expecting should return a list of every element in the original list that has an index divisible by 7. I cannot figure out how to account for the duplicates.
Any assistance with this would be much appreciated - thank you very much in advance!
Do:
>>> a = ['a', 'a', 'b' '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', 'li', 'a']
>>> [j for i,j in enumerate(a) if i%7==0]
['a', 'g', 'n', 'u', 'a']
Note that, on index 2, you have 'b' 'b' which results in 'bb'.
I think this is what you're after
for index, letter in enumerate(alphabet):
if (index % 7 == 0):
final.append(letter)
print final
Two things.
First, instead of using a list to accumulate the results, use a set. Duplicates are automatically eliminated.
And, why look at every letter instead of just at every seventh letter?
final = set()
for i in range(len(alphabet)/7):
final.add(alphabet[i*7])
print final
try this:
>>> alphabet = ['a', 'a', 'b' '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', 'li', 'a']
>>> [letter for i,letter in enumerate(alphabet) if i%7==0]
['a', 'g', 'n', 'u', 'a']

Need to reorder list and make a sentence in python

I need help rearranging this list alphabetically
list= ['z', 'a', 'b', 'y', 'c', 'x', 'd', 'w', 'e', 'v', 'f', 'g', 'u', 'h', 'i', 'j', 't' ,'k', 'l', 's', 'm', 'n', 'r', 'o', 'p', 'q', ' ']
into "hello world" by indexing into the array. How exactly do I do that? I'm a beginner and I'm doing this in python 2.7.
As has been mentioned, your list can be sorted alphabetically by using the sort() function as follows:
mylist = ['z', 'a', 'b', 'y', 'c', 'x', 'd', 'w', 'e', 'v', 'f', 'g', 'u', 'h', 'i', 'j', 't' ,'k', 'l', 's', 'm', 'n', 'r', 'o', 'p', 'q', ' ']
mylist.sort()
print mylist
Which results in your list looking like:
[' ', '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']
But you go on to say 'index into' for 'hello world'. If you mean you want to create a simple cypher then this could be easily be achieved as follows:
import string
s_from = 'abcdefghijklmnopqrstuvwxyz '
s_to = 'zabycxdwevfguhijtklsmnropq '
cypher_table = string.maketrans(s_from, s_to)
print "hello world".translate(cypher_table)
This would convert your text as follows:
wcggi rikgy
Please could you edit your question to give an example of what you are trying to achieve.
Since there is a empty element in the list. You can try to avoid them by using sorted method of list
>>> sorted(list_alphabet, key=list_alphabet.remove(' '))
['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']
sorted does create new copy of actual list and sort them. So you can refer the output of the sorted to new variable. Like
>>> sorted_list_alphabet = sorted(list_alphabet, key=list_alphabet.remove(' '))
>>> sorted_list_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']
PS: do not use list as a variable name because it brings conflict between actual list and your list variable

Sequence of letters in Python

Is there a built-in method / module in Python to generate letters such as the built-in constant LETTERS or letters constant in R?
The R built-in constant works as letters[n] where if n = 1:26 the lower-case letters of the alphabet are produced.
Thanks.
It's called string.ascii_lowercase.
If you wanted to pick n many random lower case letters, then:
from string import ascii_lowercase
from random import choice
letters = [choice(ascii_lowercase) for _ in range(5)]
If you wanted it as a string, rather than a list then use str.join:
letters = ''.join([choice(ascii_lowercase) for _ in range(5)])
You can use map as in the following:
>>> map(chr, range(65, 91))
['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']
>>> map(chr, range(97, 123))
['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']
>>> a = map(chr, range(65, 70))
>>> a
['A', 'B', 'C', 'D', 'E']
With list comprehensions and reference from the above, there is another method:
>>> [chr(x) for x in range(97, 123)]
['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']
Yet another way to do it which will give you directly a string:
>>> bytearray(range(97,123)).decode("utf-8")
u'abcdefghijklmnopqrstuvwxyz'
(it works with both python2 and python3, of course the u prefix won't be visible if it's python 3)
You can obviously tranform that string into a list like in other answers if that is what you prefer, for instance with:
>>> [x for x in bytearray(range(97,123)).decode("utf-8")]
['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']
It is also very easy to change it to pick n random letters (repetition allowed):
>>> import random
>>> n = 10
>>> bytearray(random.randint(97, 122) for x in range(n)).decode('utf-8')
'qdtdlrqidx'
Or without repetition:
>>> import random
>>> n = 10
>>> bytearray(random.sample(range(97, 123),n)).decode('utf-8')
'yjaifemwbr'

Transforming characters in Python

mir = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 't', 'u', 'v', 'x', 'y']
keq = ['.', 'c', 'z', 's', 'e', 'd', 'f', 'g', 'i', 'h', 'j', 'k', 'b', 'v', 'o', 'p', 'q', 'r', 't', 'u', 'x', ''\'', 'y']
I want to know if any of the characters in keq are pressed in raw_input('write text: ')
to transform them in characters that are shown in mir
Can someone help me do this... If you can write all the code it will help me so much
1. You could built a translation table for characters using the maketrans and translate methods, e.g.
>>> import string
>>> tb = string.maketrans('abc', '123')
>>> 'cyan banana'.translate(tb)
'3y1n 21n1n1'
2. You could concatenate all strings in an array using the ''.join method, e.g.
>>> arr = ['a', 'b', 'c']
>>> ''.join(arr)
'abc'
These should be enough to solve your problem.
mir = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 't', 'u', 'v', 'x', 'y']
keq = ['.', 'c', 'z', 's', 'e', 'd', 'f', 'g', 'i', 'h', 'j', 'k', 'b', 'v', 'o', 'p', 'q', 'r', 't', 'u', 'x', '\\', 'y']
trans = dict(zip(mir,keq))
myStr = raw_input()
print ''.join([trans.has_key(ch) and trans[ch] or ch for ch in myStr])
Create a dictionary for the transformation ...
{
'a' : '.',
'b' : 'c',
...
then use map to walk through your input, replacing keys with values.

Categories

Resources