I'm trying to group string like a map output.
Ex:
String = "
a,a
a,b
a,c
b,a
b,b
b,c"
Op:
a a,b,c
b a,b,c
Is this kind of output possible in a single step??
use the builtin sorted:
In [863]: st=sorted(String.split())
Out[863]: ['aa', 'ab', 'ba', 'bb']
to print it:
In [865]: print '\n'.join(st)
aa
ab
ba
bb
list.sort sorts the list in place and returns None, that's why when you print(lines.sort()) it shows nothing! show your list by lines.sort(); prnit(lines) ;)
Note that list.sort() sorts the list in-place, and does not return a new list. That's why
print(lines.sort())
is printing None. Try:
lines.sort() # This modifies lines to become a sorted version
print(lines)
Alternatively, there is the built-in sorted() function, which returns a sorted copy of the list, leaving the original unmodified. Use it like this:
print(sorted(list))
Because so far the other answers focus on sorting, I want to contribute this for the grouping issue:
String = """
a a
a b
a c
b a
b b
b c"""
pairs = sorted(line.split() for line in String.split('\n') if line.strip() )
from operator import itemgetter
from itertools import groupby
for first, grouper in groupby(pairs, itemgetter(0)):
print first, "\t", ', '.join(second for first, second in grouper)
Out:
a a, b, c
b a, b, c
Related
I have a list of strings. For example:
lst = ['aa bb cc', 'dd ee ff gg']
Each string in the list is known to contain 2 or more whitespace delimited tokens.
I want to build a dictionary keyed by the last token with the first token as its value.
The following dictionary comprehension achieves this:
d = {e.split()[-1]: e.split()[0] for e in lst}
This gives me:
{'cc': 'aa', 'gg': 'dd'}
...which is exactly what I want.
However, this means that the element e will have its split() function called twice per iteration over lst.
I can't help thinking that there must be a way to avoid this but I just can't figure it out.
Any ideas?
Using map:
d = {v[-1]: v[0] for v in map(str.split, lst)}
You can use walrus operator. But list comprehension is not meant to efficient, it's just shorter(I think)
lst = ['aa bb cc', 'dd ee ff gg']
d={j[-1]:j[0] for i in lst if (j:=i.split())}
print(d)
As an alternative to other answers, you can make use of unpacking to get rid of the indexing, IF the elements in your list are always going to have at least 2 strings separated by spaces (which as you say, they do), otherwise this won't work:
d = {last: first for first, *_, last in map(str.split, lst)}
print(d)
# {'cc': 'aa', 'gg': 'dd'}
If you use a function it would be much cleaner as you are carrying out an additional instruction, not just creating a list. Since you are looking to create a single holder of split values you will need to ensure there is some way to access index 0 or -1.
But it can be done like so:
d = {e[0]: e[-1] for e in [item.split() for item in lst]}
Should work for you.
Updated answer for python 3.8 +
I just recalled a recent addition on this. You can also achieve this without the inner comprehension:
d = {parts[0]: parts[-1] for e in lst if (parts := e.split())}
https://www.python.org/dev/peps/pep-0572/
I have a dictionary of the form dict[keyA][key1] where 'key1' is a dictionary of lists. i.e., keyA is a dictionary of dictionaries of lists. Below is a sample of how the dictionary could be created.
dict = { 'keyA': { 'keyA1': ['L1','L2',...], 'keyA2': ['L','L',...], ... },
'keyB': { 'keyB1': ['L1','L2',...], 'key...': ['L','L',..], ...}
}
I need to join the values of the lists together and would like to do this with a construct like:
newStr = ' A B C '.join(val for val in (dict[keyA][k] for k in dict[keyA]))
This fails with an error that val is a 'list' vs. a string.
when I resolve val via 2 for loops I get a list of strings as I would expect the above to provide.
Simple example that works for a one entry in the outer dictionary and prints a list of strings
for k in dict[keyA]:
for val in dict[keyA][k]:
print(val)
Example that does not work and prints a 'list':
for val in (dict[keyA][k] for k in dict[keyA]): print(val)
output from failing test above (note the enclosing brackets in the output). If I 'type' this value, it indicates that the value is indeed a list:
['some text', 'some more text', ....]
The working nested 'for' loops above produces the above text on separate lines without the brackets as expected, the output of which should work in the join to give the desired results....
Can anyone explain what I am missing here?
Your syntax for the "nested" comprehension isn't quite correct.
If you separate out the second portion, you'll see what's tripping it up:
>>> [_dict['keyA'][k] for k in _dict['keyA']]
[['L1', 'L2', 'L3'], ['Q1', 'Q2', 'Q3']]
The order for a nested comprehension isn't intuitive (IMO) and reads left-to-right in order of descending loops, instead of in an unrolling fashion which I think most people would initially assume.
In any case, you just need to adjust your comprehension:
>>> ' A B C '.join(val for key in _dict['keyA'] for val in _dict['keyA'][key])
'L1 A B C L2 A B C L3 A B C Q1 A B C Q2 A B C Q3'
Or using dict.items:
(Note: _ is used as a placeholder/throwaway here, since you don't actually need the "key" loop variable in this case)
>>> ' A B C '.join(val for _, v in _dict['keyA'].items() for val in v)
'L1 A B C L2 A B C L3 A B C Q1 A B C Q2 A B C Q3'
Also, as an aside, avoid using python built-ins as variable names, or you won't be able to use that built-in later on in your code.
a=[1,2,3,4]
b=[5,6,7,8]
Desired outcome from some sort of concatenation.
c=[[1,2,3,4],[5,6,7,8]]
I need this to iterable as to concatenate a different b to c numerous times whilst retaining [[,,,],[,,,],[,,,],.......]
In python you can append anything you want into a list. So for your example, we will start with an empty list c and append a and b. This method will continue to work for an arbitrary number of lists:
a = [1,2,3,4]
b = [5,6,7,8]
c = []
# Now we append
c.append(a)
c.append(b)
If we wanted to do this manually, or as a once only for fixed numbers of lists, we could just defined c as the list containing a and b like so:
c = [a, b]
I have this two unequal lists and i'm using itertools to loop through them and i'm trying to use the filter function to remove the None generated in List1 so that at the end of the day a contains only two elements instead of three (counting the none) but i keep getting this error: Type error: NoneType object is not iterable
import itertools
List1 = [['a'],['b']]
List2 = ['A','b','C']
l = list(itertools.chain(*List1))
print(l)
for a, b in itertools.zip_longest((b for a in List1 for b in a),List2):
filter(None, a)
print(a,b)
Not entirely clear what you want. As I understand the question and the comments, you want to use izip_longest to combine the lists, but without any None elements in the result.
This will filter the None from the zipped 'slices' of the lists and print only the non-None values. But note that this way you can not be sure whether, e.g., the first element in the non_none list came from the first list or the second or third.
a = ["1", "2"]
b = ["a", "b", "c", "d"]
c = ["x", "y", "z"]
for zipped in izip_longest(a, b, c):
non_none = filter(None, zipped)
print non_none
Output:
('1', 'a', 'x')
('2', 'b', 'y')
('c', 'z')
('d',)
BTW, what your filter(None, a) does: It filters the None values from your a, i.e. from the strings "a" and "b" (which does not do much, as they contain no None values), until it fails for the last value, as None is not iterable. Also, it discards the result anyway, as you do not bind it to a variable. filter does not alter the original list, but returns a filtered copy!
Why not just use zip?
for a, b in zip((b for a in List1 for b in a),List2):
print(a,b)
However, if you really insist on using zip_longest, you don't need to use filter to remove None values. You just need an if.
for a, b in itertools.zip_longest((b for a in List1 for b in a),List2):
if a is None: continue
print(a,b)
import itertools as it
def grouper(inputs, n, fillvalue=None):
iters = [iter(inputs)] * n
interim = it.zip_longest(*iters, fillvalue=fillvalue)
return interim
nums = range(23)
results = (list(grouper(nums, 4)))
finalanswer = []
for zipped in results:
# non_none = tuple(filter(None, zipped))
# unfortunately the line above filters 0 which is incorrect so instead use:
non_none = tuple(filter(lambda x: x is not None, zipped))
finalanswer.append(non_none)
print(finalanswer)
The code above uses zip_longest to illustrate generating zipped iterations of 'n' lists, irrespective of whether a corresponding entry exists in a given list or not --- and then strips out 'None' values --- noting that FILTER considers None and 0 as equivalent, so you have to use the 'lambda' version.
I stack with the following problem, I need to finding maximum between equal positions between lists. Map function works pretty well, but how to make it work for the list of the lists? using map(max,d) gave the max of the every list. The problem is that the number of the lists in the list is variable. Any suggestions are welcome!
Input for the problem is d not an a,b,c, d - is a list of the lists, and the comparison is pairwise per position in the list.
a = [0,1,2,6]
b = [5,1,0,7]
c = [3,8,0,8]
map(max,a,b,c)
# [5,8,2,8]
d = [a,b,c]
map(max,d)
[6,7,8]
a = [0,1,2,6]
b = [5,1,0,7]
c = [3,8,0,8]
print [max(itm) for itm in zip(a, b, c)]
or even shorter:
print map(max, zip(a, b, c))
How about this:
max(map(max,d))