9

I have a dictionary as follows:-

dict={'a':'1','b':'2', 'c':'3'}

To convert it into into a comma separated keys string key_string and a comma separated values string val_string I do the following:-

key_list=[]
val_list=[]

 for key,value in dict.iteritems():
     key_list.append(key)
     val_list.append(value)

 key_string = ','.join(key_list)
 val_string = ','.join(val_list)

The result is

 key_string = "a,b,c"
 val_string = "1,2,3" 

Is there a more efficient/elegant way to do this?

nimeshkiranverma
  • 1,408
  • 6
  • 25
  • 48
  • Do you want "efficient" or "elegant"? The two are often at cross purposes. And do you mean "efficient" as in "least time" or "least temporary space" or some other measure? – abarnert May 04 '15 at 07:25
  • 1
    If I tell you `val_string = ','.join(dict.values())`, I'm sure you can work out the other one... – jonrsharpe May 04 '15 at 07:25
  • Something like this? ','.join(map(lambda x:str(x), [1,2])) – Ashish Acharya May 04 '15 at 07:26
  • Are you expecting the keys/values in any particular order? – cdarke May 04 '15 at 07:30
  • 1
    @AshishAcharya: That doesn't do the separating out keys and values. And `lambda x: str(x)` is just a slower and less elegant want to write `str`. And it's not necessary anyway, given that all of his keys and values are already strings. – abarnert May 04 '15 at 07:30
  • @cdarke Specific ordering is not required as far as they ordered with respect to each other – nimeshkiranverma May 04 '15 at 07:32

4 Answers4

17

Use str.join(iterable) (Hint: don't name your dict dict):

d = {'a':'1', 'b':'2', 'c':'3'}
print(",".join(d.keys()))
print(",".join(d.values()))

Output:

c,a,b
3,1,2

Note that a dictionary has no order. So the output does not have any order you can rely on, too.

6

The obvious solution is to just use iterkeys and itervalues instead of iteritems:

key_string = ','.join(d.iterkeys())
val_string = ','.join(d.itervalues())

If you're worried about the keys and values showing up in different orders, while Python allows dicts to iterate in any order they want, it does document here that if you iterate them over and over without doing anything else between you will get the same order:

If items(), keys(), values(), iteritems(), iterkeys(), and itervalues() are called with no intervening modifications to the dictionary, the lists will directly correspond.

(The 2.7 docs were never updated to say so, but it's also true for viewitems, viewkeys, and viewvalues.)


At least in CPython, it will probably be slightly more efficient to use keys and values instead of iterkeys and itervalues (because, when given an iterator, the CPython implementation of str.join just makes a list out of it), but I doubt that matters. As Padraic Cunningham points out in the comments, for the keys (but not the values), you may be able to get the same list even faster with just list(d) instead of d.keys() (although maybe not—it avoids a LOAD_ATTR call, but at the cost of a LOAD_NAME, unless you've first copied list to a local so it can be LOAD_FASTed).


Finally, if you want to do it with iteritems (let's say you're using a broken not-quite-compliant Python interpreter that randomizes the iteration order each time), you can use zip for that:

keys, values = zip(*d.iteritems())

That turns a sequence of pairs into a pair of sequences.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 1
    You could just call "".join() on d without the call to .iterkeys although as you already said something like `list(d)` would be more efficient, also in python 3 different runs of the script can change the order of the keys and values which is different behaviour to python 2. – Padraic Cunningham May 04 '15 at 08:29
  • @PadraicCunningham: Yeah, I suppose `','.join(list(d))` would be probably the most efficient in CPython 2.7. If anyone really cared, I'd test all the possibilities, but I doubt anyone does. At any rate, for parallelism with the `itervalues()`, I think `iterkeys()` is more readable here. – abarnert May 04 '15 at 08:44
  • @PadraicCunningham: As for order between runs, actually, Python has definitely never guaranteed that you'd get the same order every run. 2.7 and 3.4 have nearly identical wording for the order. It's true that CPython 3.4 uses hash randomization for strings by default, while 2.7 (and 3.3) doesn't, but then Jython 2.5 would already give you a different order in each run, and meanwhile, there's talk of having `dict` preserve insertion order by default in CPython 3.5 (and maybe even requiring it for other implementations), so that's not really a Python 2 vs. Python 3 thing. – abarnert May 04 '15 at 08:48
  • @abarnet , I always thought on cpython 2.7 that at least for strings and ints you would always get the same order across different runs. – Padraic Cunningham May 04 '15 at 09:10
  • @PadraicCunningham: Yes, but that's something implementation-specific, not a 2.x-vs.-3.x difference. CPython 1.0-3.3 behave one way, CPython 3.4 behaves a different way, CPython 3.5 might behave a different way, Jython 2.2-2.5 behave a different way, I don't know about IronPython or Skulpt or etc. You should not assume that "Python 2" means "same order across runs", or that "Python 3" means "randomized order". – abarnert May 04 '15 at 09:16
  • @PadraicCunningham: Besides, the OP specifically said "Specific ordering is not required as far as they ordered with respect to each other", and Python 2.x and 3.x both guarantee that much (and explicitly no more than that) in the section I linked. – abarnert May 04 '15 at 09:17
2

You could do it like this:

key_string = ','.join(dict.keys()) 
val_string = ','.join(dict.values())
miindlek
  • 3,523
  • 14
  • 25
1

Using the same function str.join(iterable), if dictionary values are not all strings then using list-comprehension shorthand:

d = {'a': '1', 'b': 2, 'c': {'d': 3}, 'e': [4,5,6]}
print(",".join(d.keys()))
print(",".join([str(e) for e in d.values()]))

Output:

a,b,c,e
1,2,{'d': 3},[4, 5, 6]

If you want custom formatting then this makes for an elegant abstraction. Replace str(e) with your custom formatter myFormatter(e).

Rohit Mistry
  • 113
  • 3
  • 11
  • I posted this solution because I got exception for my dictionary: `TypeError: sequence item 1: expected str instance, int found` – Rohit Mistry Jun 09 '19 at 16:42