0

I'm looking to make a GeoJSON to return by combining 3 other GeoJSON dict objects. The three entries have the same keys but different values. For example like this

d1 = {"type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [102.0, 0.5]
      },
      "properties": {
        "prop0": "value0"
      }
    }
d2 = {"type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
        ]
      },
      "properties": {
        "prop0": "value0",
        "prop1": 0.0
      }
    }
d3 =  {"type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
            [100.0, 1.0], [100.0, 0.0]
          ]
        ]
      },
      "properties": {
        "prop0": "value0",
        "prop1": { "this": "that" }
      }
    }

The desired output is like this

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [102.0, 0.5]
      },
      "properties": {
        "prop0": "value0"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [
          [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
        ]
      },
      "properties": {
        "prop0": "value0",
        "prop1": 0.0
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
            [100.0, 1.0], [100.0, 0.0]
          ]
        ]
      },
      "properties": {
        "prop0": "value0",
        "prop1": { "this": "that" }
      }
    }
  ]
}

When I try to use methods like out.update(d1), out.update(d2) the keys overlap so all 3 dictionaries aren't appended.

funnydman
  • 9,083
  • 4
  • 40
  • 55
notmenotme
  • 51
  • 6
  • hi, what is the desired output? – jspcal Jul 20 '21 at 19:39
  • 1
    How is your desired output related to the input? Where are the keys `key1` and `key2`? – Barmar Jul 20 '21 at 19:40
  • Can you show what your desired output would be from your example? – Coin Graham Jul 20 '21 at 19:41
  • `update()` won't automatically combine values into a list. When there are duplicate keys, it just replaces it. – Barmar Jul 20 '21 at 19:41
  • @Barmar edited question so the example matches the desired output. Yes when there are duplicate keys it replaces the value. but I want to have all values for the matched keys still shown – notmenotme Jul 20 '21 at 19:54
  • Does this answer your question? [How do I merge two dictionaries in a single expression (taking union of dictionaries)?](https://stackoverflow.com/questions/38987/how-do-i-merge-two-dictionaries-in-a-single-expression-taking-union-of-dictiona) – funnydman Jul 20 '21 at 19:58

2 Answers2

1

I've deleted my previous answer as I misunderstood your question. After the edit you've made I am now clear what you really expected is nothing but combining the dicts as a list. So the code with this three dicts will be nothing but:

dd = defaultdict(list)

featureNode = [d1,d2,d3]

dd['features'] = featureNode
dd['type'] = "FeatureCollection"

print(dd)

And you'll get your desired output.

devReddit
  • 2,696
  • 1
  • 5
  • 20
0

update doesn't look at values at all; it's only concerned with merge the keys sets. If you want to merge the values of existing keys, you need to do that yourself.

For example, you might want to consolidate the values in a list:

merged = {}
for d in [d1, d2, d3]:
    for key in d:
        merged.setdefault(key, []).append(d[key])

or you might want to sum the values:

merged = defaultdict(int)
for d in [d1, d2, d3]:
    for key in d:
        merged[key] += d[key]

etc. In general, you could define a function that takes a combining function:

from operator import add

def accumulate(x, y):
    if isinstance(x, list):
        return x + [y]
    else:
        return [x, y]

def merge(f, *dicts):
    m = {}
    for d in dicts:
        for key in d:
            if key not in m:
                m[key] = d[key]
            else:
                m[key] = f(m[key], d[key])
    return m

merged1 = merge(accumulate, d1, d2, d3)
merged2 = merge(operator.add, d1, d2, d3)

You can see how this can get more complicated if you need different combining functions for each key, so it should not be surprising that there is not a single, built-in way to merge dicts by value.

chepner
  • 497,756
  • 71
  • 530
  • 681