如何根据条件合并字典?

时间:2019-06-17 10:06:33

标签: python python-3.x

说我有以下词典列表:

x = [{
  '218': {
    'text': 'profit',
    'start': 0,
    'end': 21
  }
}, {
  '312': {
    'text': 'for',
    'start': 30,
    'end': 60
  }
}, {
  '350': {
    'text': 'year',
    'start': 70,
    'end': 85
  }
}, {
  '370': {
    'text': 'next column',
    'start': 120,
    'end': 130
  }
}, {
  '385': {
    'text': 'next_column',
    'start': 160,
    'end': 169
  }
}]

我想合并一些词典,条件是每当第一个dict的末尾与下一个dict的开始的差小于我合并所有{{1 }},并连接所有文本。

输出应如下所示:

dict

我已经用基本方法解决了它,但是看起来并不好,是否有使用x_new = [{ '218,312,350': { 'text': 'profit for year', 'start': 0, 'end': 85 } }, { '370': { 'text': 'next column', 'start': 120, 'end': 130 } }, { '385': { 'text': 'next_column', 'start': 160, 'end': 169 } }] 或类似方法的解决方案?

我尝试过的

itertools

一旦我有了final_merge,它就会告诉我要合并的值,很容易添加值。但是对于上面的代码,有什么简单的方法。此外,在循环结束后,我手动添加了最后一个字典,因为在我的情况下,最后一个字典始终是不同的列,但是如果它属于同一列呢? >

3 个答案:

答案 0 :(得分:0)

尝试一下:

x=[{'218':{'text':'profit','start':0,'end':21}},
   {'312':{'text':'for','start':30,'end':60}},
   {'350':{'text':'year','start':70,'end':85}},
   {'370':{'text':'next column','start':120,'end':130}},
   {'385':{'text':'next_column','start':160,'end':169}}]

x_new = []
d_keys = []
first_start_value = 0

def merge_dict(d_keys,x,i,first_start_value,current_index_dict_key):
    # remove duplicate list of string
    d_keys = list(set(d_keys))

    # sort list by number
    d_keys.sort(key=int)
    new_key = ','.join(d_keys)

    # update start value
    x[i][current_index_dict_key]['start'] = first_start_value
    dict1 = {new_key: x[i][current_index_dict_key]}
    return  dict1

for i in range(0,len(x)):
    current_index_dict_key = list(x[i].keys())[0]

    #check next index of list is valid
    if i+1 > len(x)-1:
        if len(d_keys) > 0:
            # merge dictionary
            dict1 = merge_dict(d_keys, x, i, first_start_value, current_index_dict_key)
            x_new.append(dict1)
            break

        dict1 = {current_index_dict_key: x[i][current_index_dict_key]}
        x_new.append(dict1)
        break

    next_index_dict_key = list(x[i+1].keys())[0]
    start = x[i+1][next_index_dict_key]['start']
    end = x[i][current_index_dict_key]['end']
    diff = start - end

    #compare current and next list of dicstionary end and start value
    if diff < 20:
        if len(d_keys) <= 0 and i == 1:
            first_start_value = x[i][current_index_dict_key]['start']

        d_keys.append(current_index_dict_key)
        d_keys.append(next_index_dict_key)
    else:

        if len(d_keys) > 0:
            # merge dictionary
            dict1 = merge_dict(d_keys,x,i,first_start_value,current_index_dict_key)
            d_keys = []
            first_start_value = x[i][current_index_dict_key]['start']
        else:
            dict1 = {current_index_dict_key: x[i][current_index_dict_key]}

        x_new.append(dict1)

print(x_new)

O / P:

[
  {
    '218,312,350': {
      'text': 'year',
      'start': 0,
      'end': 85
    }
  },
  {
    '370': {
      'text': 'next column',
      'start': 120,
      'end': 130
    }
  },
  {
    '385': {
      'text': 'next_column',
      'start': 160,
      'end': 169
    }
  }
]

答案 1 :(得分:0)

我将为您使用的这些对象创建一个类:

class my_dict:
    __init__(self, id, text, start, end):
        self.id = id
        self.text = text
        self.start = start
        self.end = end

    merge(self, other):
        self.id = "{},{}".format(self.id, other.id)
        self.text = "{} {}".format(self.text, other.text)
        self.end = other.end

然后主代码循环将是:

x_new = [x[0]]
for obj in x[1:]:
    last = x_new[-1]
    if obj.start - last.end > 20:
        x_new.append(obj)
    else:
        last.merge(obj)

答案 2 :(得分:0)

这就是我要做的:

首先,我将提供一些辅助功能:

def merge(d1, d2):
    return {",".join([list(d1)[0], list(d2)[0]]): {'text': " ".join([list(d1.values())[0]['text'], list(d2.values())[0]['text']]), 'start': list(d1.values())[0]['start'], 'end': list(d2.values())[0]['end']}}

def should_merge(d1, d2):
    if (d1 is None) or (d2 is None):
        return False
    return abs(list(d1.values())[0]['end'] - list(d2.values())[0]['start']) < 20

第一个函数合并了两个字典

如果两个字典应该合并,则第二个返回True。

剩下的就是实际的合并功能:

from itertools import zip_longest
def merged_dicts(x):
    actual_merge = []
    last_merged = False
    for d1, d2 in zip_longest(x, x[1:], fillvalue=None):
        if should_merge(d1, d2) and last_merged:
            actual_merge.append(merge(actual_merge.pop(), d2))
        elif should_merge(d1, d2):
            actual_merge.append(merge(d1, d2))
            last_merged = True
        elif last_merged:
            last_merged = False
        else:
            actual_merge.append(d1)
            last_merged = False
    print(actual_merge)

尽管它不使用任何“花哨”的itertool函数,但可读性更高。

我还考虑将dict的id更改为内部dict:

d= {'id': '385',
    'text': 'next_column',
    'start': 160,
    'end': 169
  }

这有点复杂和清洁。