defaultdict(list) concatenating all the values into one list - python

What I am trying to do:
Write a method to sort an array of strings so that all the anagrms are
next to each other.
I have the following code:
from collections import defaultdict
res = defaultdict(list)
L = ['foo', 'poo', 'k', 'fo', 'ofo', 'oof']
for w in L:
res["".join(sorted(w))].append(w)
But now I want to take all the values in res and combine them into one list.
I tried this:
output =[]
for items in res.values():
output.append(i for i in items)
But that gave me:
>>> output
[<generator object <genexpr> at 0x102a4d1e0>, <generator object <genexpr> at 0x102a95870>, <generator object <genexpr> at 0x102a958c0>, <generator object <genexpr> at 0x102a95910>]
How can I display the items in one list properly?
Desired:
['foo','ofo', 'oof','poo', 'k', 'fo',]
(all the anagrams are together, order doesn't matter as long as they are adjacent in the list.)

When you do -
output.append(i for i in items)
You are actually appending the generator expression - i for i in items - into output list, as you can also see from the repr result of your output list. This does not automatically evaluate the generator expression and add the results. What you should have done was to use output.extend(). Example -
>>> output = []
>>> for items in res.values():
... output.extend(items)
...
>>> output
['fo', 'k', 'foo', 'ofo', 'oof', 'poo']
This would evaluate the expression and append each element from the iterable (generator expression) to the list as a separate element.
But If you want to convert a single list from all the list values of res dictionary, An much easier way would be to use itertools.chain.from_iterable. Example -
>>> from itertools import chain
>>> output = list(chain.from_iterable(res.values()))
>>> output
['fo', 'k', 'foo', 'ofo', 'oof', 'poo']

EDITED
I believe that replacing
output.append(i for i in items)
with
output.extend(items)
will do what you expect.

Related

Why do the list function and list literals act differently?

I was trying to create a list with n empty lists inside of it, but faced an interesting situation.
Firstly I tried the following:
>>> n = 3
>>> list([]) * n
[]
It creates an empty list.
After that I tried the following line, which creates an empty list, too:
>>> list(list()) * n
[]
But when I try the same with literals,
>>> [[]] * n
[[], [], []]
it gives the correct output. Can someone explain why?
list(...) is not interchangeable with [...]. You can wrap square brackets around things to get nested lists, but wrapping things in list() doesn't have the same effect.
When you write [[]] you get a list with a single element. That element is [].
When you write list([]) the list constructor takes an iterable and creates a list with the same elements. If you wrote list(['foo', 'bar']) the result would be ['foo', 'bar']. Writing list([]) yields [].
This form is more useful when you pass iterables that aren't lists. Other examples:
list('abc') == ['a', 'b', 'c'] # strings are iterables over their characters
list(('foo', 'bar')) == ['foo', 'bar'] # tuple
list({'foo', 'bar'}) == ['foo', 'bar'] # set; could get ['bar', 'foo'] instead
list(list()) is equivalent to list([]). And we've seen that's in turn equivalent to [].
Stay away from [[]] * n when creating a multidimensional list. It will create a list with n references to the same list object and will bite you when you try to modify the internal lists. It's a common mistake that everyone makes. Use this instead, which will create a separate empty list for each slot:
[[] for i in range(n)]
Further reading:
How to create a multi-dimensional list
List of lists changes reflected across sublists unexpectedly

python groupby and list interaction

If we run the following code,
from itertools import groupby
s = '1223'
r = groupby(s)
x = list(r)
a = [list(g) for k, g in r]
print(a)
b =[list(g) for k, g in groupby(s)]
print(b)
then surprisingly the two output lines are DIFFERENT:
[]
[['1'], ['2', '2'], ['3']]
But if we remove the line "x=list(r)", then the two lines are the same, as expected. I don't understand why the list() function will change the groupby result.
The result of groupby, as with many objects in the itertools library, is an iterable that can only be iterated over once. This is to allow lazy evaluation. Therefore, when you call something like list(r), r is now an empty iterable.
When you iterate over the empty iterable, of course the resulting list is empty. In your second case, you don't consume the iterable before you iterate over it. Thus, the iterable is not empty.

Python IZIP list comprehension returns empty list

I have a list of strings that I am sorting. There are 12 different key strings within the list that I am using to sort by. So instead of writing 12 separate list comprehensions I would like to use a list of empty lists and a list of key strings to sort, then use izip to perform list comprehensions. Here is what I am doing:
>>> from itertools import izip
>>> tran_types = ['DDA Debit', 'DDA Credit']
>>> tran_list = [[] for item in tran_types]
>>> trans = get_info_for_branch('sco_monday.txt',RT_NUMBER)
>>> for x,y in izip(tran_list, TRANSACTION_TYPES):
x = [[item.strip() for item in line.split(' ') if not item == ''] for line in trans if y in line]
>>> tran_list[0]
[]
I would like to see an output more like the following:
>>> tran_list[0]
[['DDA Debit','0120','18','3','83.33'],['DDA Debit','0120','9','1','88.88']]
The output doesn't make sense to me; the objects that izip returns are lists and strings
>>> for x,y in itertools.izip(tran_list, TRANSACTION_TYPES):
type(x), type(y)
(<type 'list'>, <type 'str'>)
(<type 'list'>, <type 'str'>)
Why is this process returning empty lists?
A variable is much like a sticker.
You can have multiple stickers placed on the same thing:
>>> a=b=[] #put stickers a and b on the empty list
>>> a.append(1) #append one element to the (previously) empty list
>>> b #what's the value of the object the b sticker is attached to?
[1]
And can have things that have no sticker at all:
>>> a=[1,2,3]
>>> a="" #[1,2,3] still exists
Although they're not very useful, since you can't refer to them - so they are eventually garbage collected.
>>> for x,y in izip(tran_list, TRANSACTION_TYPES):
x = [[item.strip() for item in line.split(' ') if not item == ''] for line in trans if y in line]
Here, you have a sticker with a x in it. When you assign (x=...), you're changing the placement of the sticker - not modifying the place where the sticker originally was placed on.
You're assigning to a variable that is, in turn, assigned each time the for loop cycles.
Your assignment has absolutely no effect.
This is true for any kind of for loop in python, and bears no connection to izip in particular.
It looks like you're trying to stuff the variable x back into tran_list after it's been zipped, but izip only guarantees that the returned type is an iterator, not that it's a strict pointer back to the original list. You may be losing all the work you're doing inside the for loop without realizing it.

Python convertion of list of strings to list of tuples

How to convert following list
['abc,cde,eg,ba', 'abc,cde,ba']
in to list of tuples?
[('abc','cde','eg','ba'), ('abc','cde','ba')]
What I have tried
output = []
for item in my_list:
a = "','".join((item.split(',')))
output.append(a)
In your loop, you are splitting the string (which will give you a list), but then you are joining it back with a ,, which is returning to you the same string:
>>> 'a,b'.split(',')
['a', 'b']
>>> ','.join('a,b'.split(','))
'a,b'
You can convert a list to a tuple by passing it to the the built-in tuple() method.
Combining the above with a list comprehension (which is an expression that evaluates to a list), gives you what you need:
>>> [tuple(i.split(',')) for i in ['abc,cde,eg,ba', 'abc,cde,ba']]
[('abc', 'cde', 'eg', 'ba'), ('abc', 'cde', 'ba')]
The longhand way of writing that is:
result = []
for i in ['abc,cde,eg,ba', 'abc,cde,ba']:
result.append(tuple(i.split(',')))
print(result)
t=['abc,cde,eg,ba', 'abc,cde,ba']
for i in t:
print tuple(i.split(','))
you can split the 2 elements. Here is my code
['abc,cde,eg,ba', 'abc,cde,ba']
a='abc,cde,eg,ba'
b='abc,cde,ba'
c=[]
c.append(tuple(a.split(',')))
c.append(tuple(b.split(',')))
print c

iterating over two lists to create a new list in Python

I'm trying to iterate over two lists to populate a new list with the outcome, but am not sure where it's going wrong. Note: i'm a beginner using Python. Mahalo in advance!
sumList = [27400.0, 32900.0, 42200.0, 40600.0];
volList = [27000.0, 40000.0, 31000.0, 40000.0];
rendeList = [];
x = 0;
for sumValue in range (0, len(sumList)-1):
rendeList = rendeList.append((sumList[x]/volList[x])*100)
x += 1;
However, I get an Attribute Error: 'NoneType' object has no attribute 'append'. After running the for loop, i get:
print rendeList
None
My expected outcome would have been:
print rendeList
[101.48, 82.25, 136.13, 101.49]
list.append(x) modifies the list and returns None.
Change your code to:
for sumValue in range (0, len(sumList)):
rendeList.append((sumList[x]/volList[x])*100)
x += 1
Or simplify it to:
for sumValue, volValue in zip(sumList, volList):
rendeList.append((sumValue / volValue) * 100)
Here is your solution using list comprehension:
result = [a[0]/a[1]*100 for a in zip(sumList, volList)]
The root of your problem is that list.append returns None
>>> a_list = list('abc')
>>> print(a_list.append('d'))
None
>>> a_list
['a', 'b', 'c', 'd']
And if you reassign a_list:
>>> a_list = a_list.append('e')
>>> a_list
>>> print(a_list)
None
Python's map function would be perfect for this:
rendeList = map(lambda x,y: x/y*100, sumList, volList)
The map function returns a list where a function (the first argument, which here I've supplied as a Lambda expression) is applied to each element of the passed in list, or in this case each pair of elements from the two lists passed in.

Categories

Resources