A more pythonic way of writing this recursive function

This function is designed to use a generic dictionary (which can, recursively, contain other dictionaries and lists) and put all its contents into one linear list.

def make_a_list(a):
  print type(a)
  if (type(a) == type({})):
    return make_a_list(a.keys()) + make_a_list(a.values())
  elif (type(a) == type([])):
    if len(a) > 1:
      return make_a_list(a[0]) + make_a_list(a[1:])
    return a
  else:
    return [a]

He did his job, but I wonder: a) Have I forgotten about any important data types? (for example, I forgot a lot) b) what would be a more pythonic way to write it? (especially if I can write a list comprehension?)

+4
source share
3 answers

You can avoid creating a list / concatenation in your function with yield.

def make_a_list(a):
  if isinstance(a, dict):
    yield from make_a_list(a.keys())
    yield from make_a_list(a.values())
  elif isinstance(a, (list, tuple, set)):
    for x in a:
      yield from make_a_list(x)
  else:
    yield a

This is a generator, so if you really need a list, you can do:

def make_a_real_list(a):
    return list(make_a_list(a))

, isinstance , .

+2

, /.

-, , , __iter__.

:

things_to_flatten = []
things_to_flatten.append(a)
new_list = []
while things_to_flatten:
  current = things_to_flatten.pop(0)
  if isinstance(current, dict):
      things_to_flatten.extend(current.keys())
      things_to_flatten.extend(current.values())
  elif hasattr(current, '__iter__'):
      things_to_flatten.extend(current)
  else:
      new_list.append(current)

, , , , , dicts lists. , , ... .

0

? main make_a_list , . , test flatten , . , .

#! /usr/bin/env python3
def main():
    obj = 1
    print('make_a_list({!r}) = {!r}'.format(obj, make_a_list(obj)))
    obj = {1, 2, 3}
    print('make_a_list({!r}) = {!r}'.format(obj, make_a_list(obj)))
    obj = [1, 2, 3]
    print('make_a_list({!r}) = {!r}'.format(obj, make_a_list(obj)))
    obj = [1]
    print('make_a_list({!r}) = {!r}'.format(obj, make_a_list(obj)))
    obj = 'a', 'b', 'c'
    print('make_a_list({!r}) = {!r}'.format(obj, make_a_list(obj)))
    obj = {1: 2, 3: 4, 5: 6}
    print('make_a_list({!r}) = {!r}'.format(obj, make_a_list(obj)), end='\n\n')


def make_a_list(obj):
    if isinstance(obj, dict):
        return make_a_list(list(obj.keys())) + make_a_list(list(obj.values()))
    if isinstance(obj, list):
        if len(obj) > 1:
            return make_a_list(obj[0]) + make_a_list(obj[1:])
        return obj
    return [obj]


def test():
    obj = 1
    print('list(flatten({!r})) = {!r}'.format(obj, list(flatten(obj))))
    obj = {1, 2, 3}
    print('list(flatten({!r})) = {!r}'.format(obj, list(flatten(obj))))
    obj = [1, 2, 3]
    print('list(flatten({!r})) = {!r}'.format(obj, list(flatten(obj))))
    obj = [1]
    print('list(flatten({!r})) = {!r}'.format(obj, list(flatten(obj))))
    obj = 'a', 'b', 'c'
    print('list(flatten({!r})) = {!r}'.format(obj, list(flatten(obj))))
    obj = {1: 2, 3: 4, 5: 6}
    print('list(flatten({!r})) = {!r}'.format(obj, list(flatten(obj))))


def flatten(iterable):
    if isinstance(iterable, (list, tuple, set, frozenset)):
        for item in iterable:
            yield from flatten(item)
    elif isinstance(iterable, dict):
        for item in iterable.keys():
            yield from flatten(item)
        for item in iterable.values():
            yield from flatten(item)
    else:
        yield iterable


if __name__ == '__main__':
    main()
    test()
0

Source: https://habr.com/ru/post/1666047/


All Articles