Search code examples
pythondictionary-comprehension

How would I achieve this dict comprehension of two keys with list values using zip?


I've been trying for the past while to convert a code snippet I have into code comprehension, not because it is faster or more beneficial, but because it would help me understand Python more.

I have a generator that I'm reading from that contains 2 values, 1 value for EN, and 1 value for AR (Languages). I want to map the values inside into a new dictionary with 2 keys EN and AR that contains the list of values per language. The languages are specified from a config file under the name SupportedLanguages: SupportedLanguages = ["en", "ar"].

I know that in Javascript something similar can be done using the map and reduce functions, but I'm unsure how to do that here in Python, and nothing of what I've tried seems to be doing what I want.

Here is the current code snippet that I have:

reader = ([i, str(i)] for i in range(10))
rows = [row for row in reader]
SupportedLanguages = ["en", "ar"]

dict_ = {
    "en": []
    "ar": []
}

for row in rows:
  for i, _ in enumerate(row):
    dict_[SupportedLanguages[i]].append(row[i])
    

reader is a dummy generator to replicate the behavior of my csv reader (since I have n rows, where n depends on the number of languages I have).

The working solution that I have come up with is this comprehension:

{SupportedLanguages[i]: [row[i] for row in rows] for i in range(len(row))}

However, this is looping over rows twice, and I don't want this behavior, I just need a single loop given that the generator will only loop once as well (csv.reader). I know that I can store all the values into a list before looping over them, but then again this creates n loops, and I only want 1.

Edit: As I mentioned above it is creating 2 loops, but what I should've said is n loops, as in 1 loop per language.


Solution

  • I think I understand what you're trying to achieve. Let's say you have a reader that looks like this:

    reader = ([en_value, ar_value] for en_value, ar_value in enumerate("abcdefg"))
    
    for pair in reader: # Don't actually do this part - print just for demonstration
        print(pair)
    

    Output:

    [0, 'a']
    [1, 'b']
    [2, 'c']
    [3, 'd']
    [4, 'e']
    [5, 'f']
    [6, 'g']
    >>> 
    

    Then you can construct your dict_ in the following way:

    supported_languages = ["en", "ar"]
    
    dict_ = dict(zip(supported_languages, zip(*reader)))
    print(dict_)
    

    Output:

    {'en': (0, 1, 2, 3, 4, 5, 6), 'ar': ('a', 'b', 'c', 'd', 'e', 'f', 'g')}
    >>> 
    

    Based on the observation that...:

    a, b = zip(*reader)
    print(a)
    print(b)
    

    ...yields:

    (0, 1, 2, 3, 4, 5, 6)
    ('a', 'b', 'c', 'd', 'e', 'f', 'g')
    >>>