0

This is my Ruby code. I want to convert this function to a Python 3 equivalent.

files = {
  'Input.txt' => 'Randy',
  'Code.py' => 'Stan',
  'Output.txt' => 'Randy'
}    

def group_by_owners(files)
  files.each_with_object({}) { |(key, value), new_hash| (new_hash[value] ||= []) << key }
end

puts group_by_owners(files)

The Ruby result looks like this:

{"Randy" => ["Input.txt", "Output.txt"], "Stan" => ["Code.py"]}

Python would be:

{"Randy": ["Input.txt", "Output.txt"], "Stan": ["Code.py"]}

Here is what I have tried:

def group_by_owners(files):
  new_dict = dict(zip(files.values(), (files.keys())))
  print(new_dict)

Then I was trying to append the keys to an array.

def group_by_owners(files):
  keys_array = []
  new_dict = dict(zip(files.values(), keys_array.append((files.keys()))))

but I don't think that will work inside of a zip method.

beelarr
  • 19
  • 1
  • 2

3 Answers3

1

In Python, your mentioned data structure is known as dictionary (dict in terms of code) and is syntactically represented as:

files = {
   'Input.txt': 'Randy',
   'Code.py': 'Stan',
   'Output.txt': 'Randy'
}

In order to swap the key and values of your dict, you may use collections.defaultdict as:

from collections import defaultdict

swapped_dict = defaultdict(list)

for key, value in files.items():
    swapped_dict[value].append(key) 

where swapped_dict is a dict object holding the value:

{
    'Randy': ['Output.txt', 'Input.txt'],
    'Stan': ['Code.py']
}

Note: Ruby maintains the order, but in Python version < 3.6, the dict objects are unordered in nature. However, from Python version >= 3.6, dict objects are now ordered in nature.

For Python versions < 3.6, we have collections.OrderedDict which maintains the order in which keys are inserted. Here's an example to show the swapping of key/value pairs:

from collections import OrderedDict

# for maintaining the order, your initial list 
# should also be of the type `OrderedDict`
old_dict = OrderedDict([('Input.txt', 'Randy'), ('Code.py', 'Stan'), ('Output.txt', 'Randy')])

for k, v in old_dict.items():
    new_dict.setdefault(v, []).append(k)
    # You may use `setdefault` on normal dictionaries too

which will return dict object as:

>>> new_dict
OrderedDict([('Randy', ['Input.txt', 'Output.txt']), ('Stan', ['Code.py'])])

It is just represented like this, you can access new_dict like a normal dictionary object.

Moinuddin Quadri
  • 46,825
  • 13
  • 96
  • 126
0
def group_by_owners(files: dict): -> dict
    res = {v: [] for v in files.values() }
    for k, v in files.items():
        res[v].append(k)
    return res

Note: in Python dicts are unordered (until 3.7 version).

Mark Mishyn
  • 3,921
  • 2
  • 28
  • 30
  • Dicts will be ordered as of two weeks ago: https://mail.python.org/pipermail/python-dev/2017-December/151283.html This will become part of the Python 3.7 spec, and all conforming implementations of Python 3.7 must implement it. – Jörg W Mittag Jan 01 '18 at 17:51
  • @JörgWMittag thank you. Updated. – Mark Mishyn Jan 01 '18 at 18:05
0

This is a dictionary version of files in Python:

files = {'Input.txt': 'Randy',
         'Code.py': 'Stan',
         'Output.txt' : 'Randy'}

files.items() returns:

dict_items([('Input.txt', 'Randy'), ('Code.py', 'Stan'), ('Output.txt', 'Randy')])

def group_by_owners(files):    
    result = dict() # empty dict

    for k, v in files.items(): 
        if v in result:
            result[v].append(k) # Append to list value if the key is in result
        else:
            result[v] = [k]  # Add key: value        

    return result


print(group_by_owners(files))
# {'Randy': ['Input.txt', 'Output.txt'], 'Stan': ['Code.py']}
srikavineehari
  • 2,502
  • 1
  • 11
  • 21