0

I am building a list in python by looping through some JSON blobs and appending elements. Sometimes the elements are single, sometimes double (or more).

my_list = []    
for j in jsons:
  my_list.append(j['foo'])

my_list ends up being ['a1', 'b1', ['c1', 'c2']]

If I use extend instead I get ['a', '1', 'b', '1', 'c1', 'c2'].

Do I have to first check if what I'm appending is a list, and then append it element-wise? Or is there a better function that already does this?

ScottieB
  • 3,958
  • 6
  • 42
  • 60
  • 6
    explicitly checking seems reasonable enough, given the unreasonable irregularity of your JSON blobs. But I would check if it is a list, then `.extend`, otherwise, `.append`. Another approach is to just flatten later... but probably best just to check. – juanpa.arrivillaga Sep 08 '17 at 18:22
  • Why isn't the data organized consistently to begin with? Maybe you can fix the code that creates it. – Barmar Sep 08 '17 at 18:27
  • Would that I could @Barmar , but it's public data provided by a government. – ScottieB Sep 08 '17 at 18:28
  • This might work too `[items for i in jsons for items in (i['foo'] if isinstance(i['foo'],list) else [i['foo']])]` – AsheKetchum Sep 08 '17 at 18:41
  • @AsheKetchum yes, that would work, but that is *exactly what he said by checking....* – juanpa.arrivillaga Sep 08 '17 at 18:50
  • @juanpa.arrivillaga ok? I'm sorry I don't quite get your point. I thought it was straightforward that we needed to check, so I provided a way to do it. – AsheKetchum Sep 08 '17 at 18:53

2 Answers2

3

Yes, you need to explicitly check each item type.

For instance, you can write:

# sample jsons
jsons = [{'foo': 'a1'},
         {'foo': 'b1'},
         {'foo': ['c1', 'c2']}]

my_list = []
for json in jsons:
    item = json['foo']
    if isinstance(item, list):
        my_list.extend(item)
    else:
        my_list.append(item)

You get:

['a1', 'b1', 'c1', 'c2']

But, with Python you can use a ternary conditional expression to simplify:

my_list = []
for json in jsons:
    item = json['foo']
    my_list.extend(item if isinstance(item, list) else [item])
Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
  • You can also use the ternary expression to select the correct method to call, which avoids creating the temporary list to wrap `item`. `(mylist.extend if isinstance(item, list) else mylist.append)(item)`. – chepner Sep 08 '17 at 18:36
  • You right, it's unusual and can be considered an advanced usage… ;-) – Laurent LAPORTE Sep 08 '17 at 18:39
2

You can use the singledispatch decorator to move some of the boilerplate out of your main loop. The decorator is available from the functools module in the standard library starting in Python 3.4, or via the singledispatch module on PyPi.

This defines a function adder which behaves differently depending on the type of its (first) argument.

@singledispatch
def adder(item):
    mylist.append(item)

@adder.register(list)
def _(item):
    mylist.extend(item)

mylist = []
for json in jsons:
    adder(json['foo'])
chepner
  • 497,756
  • 71
  • 530
  • 681