Home > database >  Matching key, value of two lists of dictionaries
Matching key, value of two lists of dictionaries

Time:10-30

Given two lists of dictionaries, such as -

poo = [{
      "xmin":10,
      "ymin":100,
      "xmax":70,
      "ymax":120,
      "text":"fish",
}]

And also

foo = [{
      "class":"Animal",
      "percent":88.25,
      "box_points":[30, 90, 80, 110]
}]

To produce an output like:

poofoo = [{
    "class":"Animal",
    "text":"fish",
    "percent": 88.25,
    "box_points":{
          "xmin":10,
          "ymin":90,
          "xmax":80,
          "ymax":120}
]}

Knowing that the box_points in foo list of dictionaries is also in the format xmin, ymin, xmax, ymax. These box points are coordinates of bounding boxes detected by the system.

How could one access the nested elements, compare them and then merge the elements? The idea is to merge them if they are spatially close, in this example, a threshold of 10 units (x,y).

I already tried this:

def boxOverlap(box1, box2):
    try:
        if(box1[0]<=box2[2] and box1[0]>=box2[0]) \
            or (box1[1]<=box2[3] and box1[1]>=box2[3]):
            return True
        else:
            return False
    except TypeError:
        print(f"{message_error}")

final_json = []

for el1, el2 in zip(foo, poo):        
    el1_box_format = [el1['x_min'], el1['y_min'], el1['x_max'], el1['y_max']]
    
    if(boxOverlap(el1_box_format, el2['box_points'])):
        final_json.append({"class":el2["name"],
                           "text":el1["text"],
                           "confidence":el2["percentage_probability"],
                           "boxpoints":None
                          })

Note that, I created a function to return a boolean if the boxes overlap or not (later I will implement the threshold). But the problem is, I want to compare the dictionaries only if they are spatially close, and right now, as I am using zip(foo, poo) it operates only in pairwise elements.

CodePudding user response:

A simple solution would look like below.

poo = [{
    "xmin": 10,
    "ymin": 100,
    "xmax": 70,
    "ymax": 120,
    "text": "fish",
}]

foo = [{
    "class": "Animal",
    "percent": 88.25,
    "box_points": [30, 90, 80, 110]
}]


def merge(p: dict, f: dict):
    coords = list(p.values())[:-1]
    box_coords = f.get("box_points")
    box_points = {"xmin": min(coords[0], box_coords[0]),
                  "ymin": min(coords[1], box_coords[1]),
                  "xmax": max(coords[2], box_coords[2]),
                  "ymax": max(coords[3], box_coords[3]),

                  }
    f['box_points'] = box_points
    f['text'] = p.get('text')
    return f


poofoo = [merge(poo[index], foo[index]) for index in range(len(poo))]

Output:

[
    {
        "class": "Animal",
        "percent": 88.25,
        "box_points": {
            "xmin": 10,
            "ymin": 90,
            "xmax": 80,
            "ymax": 120
        },
        "text": "fish"
    }
]

This assumes the length of both list are same, the order of coordinates are also same all the way.

CodePudding user response:

This is not a really general solution, for this too much was unclear to me.

poo = [{
      "xmin":10,
      "ymin":100,
      "xmax":70,
      "ymax":120,
      "text":"fish",
}]

foo = [{
      "class":"Animal",
      "percent":88.25,
      "box_points":[30, 90, 80, 110]
}]

foo[0]["xmin"] = foo[0]["box_points"][0]
foo[0]["ymin"] = foo[0]["box_points"][1]
foo[0]["xmax"] = foo[0]["box_points"][2]
foo[0]["ymax"] = foo[0]["box_points"][3]
foo[0].pop("box_points")


poofoo = [{}]

for kp in poo[0]:
    for kf in foo[0]:
       if kp == kf:
           if kp not in poofoo[0]:
               if abs(poo[0][kp] - foo[0][kf]) < 10:
                   poofoo[0][kp] = poo[0][kp] #change if the smallest value for the mins is needed and the biggest value for maxs
       else:
           if kp not in poofoo:
               poofoo[0][kp] = poo[0][kp]
           if kf not in poofoo:
               poofoo[0][kf] = foo[0][kf]
    
  • Related