将值列表转换为Python中的间隔列表

时间:2017-10-10 13:42:14

标签: python

我有一个对象列表,每个对象包含flag(布尔值)和value(整数)。每个列表项的值都在增加。我想将列表转换为一个新列表,只有每次flag属性交替时的第一个和最后一个value属性(间隔)。

换句话说,我想转换这个

[
    {'flag': True, 'value': 0},
    {'flag': True, 'value': 5},
    {'flag': True, 'value': 10}, 
    {'flag': False, 'value': 15}, 
    {'flag': False, 'value': 20},
    {'flag': False, 'value': 25}, 
    {'flag': False, 'value': 30},
    {'flag': False, 'value': 35},
    {'flag': False, 'value': 40}, 
    {'flag': True, 'value': 45},
    {'flag': True, 'value': 50},
    {'flag': True, 'value': 55}, 
    {'flag': True, 'value': 60},
    {'flag': False, 'value': 65},
    {'flag': False, 'value': 70}, 
    {'flag': False, 'value': 75},
    {'flag': False, 'value': 80},
    {'flag': False, 'value': 85}, 
    {'flag': True, 'value': 90},
    {'flag': True, 'value': 95}
]

进入这个(或类似的东西):

[
    {'flag': True, 'values': (0, 10)}, 
    {'flag': False, 'values': (15, 40)}, 
    {'flag': True, 'values': (45, 60)}, 
    {'flag': False, 'values': (65, 85)}, 
    {'flag': True, 'values': (90, 95)}, 
]

在Python中解决这个问题的简单而优雅的方法是什么?

我希望示例数据不会太混乱。我尝试使用for-loop和使用reduce来解决这个问题,但两种解决方案似乎都没有。

谢谢!

3 个答案:

答案 0 :(得分:3)

您可以使用itertools.groupbyflag对项目进行分组,然后将这些组转换为列表,并获取这些列表的第一个和最后一个元素的值。在这里,lst是您的原始列表。

>>> [{"flag": key, "values" : (val[0]["value"], val[-1]["value"])} 
...  for key, val in ((key, list(val)) for key, val in itertools.groupby(lst, key=lambda d: d["flag"]))]
[{'flag': True, 'values': (0, 10)},
 {'flag': False, 'values': (15, 40)},
 {'flag': True, 'values': (45, 60)},
 {'flag': False, 'values': (65, 85)},
 {'flag': True, 'values': (90, 95)}]

或者类似地,使用内部列表解析首先提取value键,因为我们必须使用内部生成器表达式将组迭代器转换为列表。结果是一样的。

>>> [{"flag": key, "values" : (vals[0], vals[-1])}
...  for key, vals in ((key, [g["value"] for g in grp]) 
...                    for key, grp in itertools.groupby(lst, key=lambda d: d["flag"]))]

但这仍然远远不可读,所以我建议将其分为两行:

>>> groups = ((key, [g["value"] for g in grp])
...           for key, grp in itertools.groupby(lst, key=lambda d: d["flag"]))
>>> result = [{"flag": key, "values" : (vals[0], vals[-1])} for key, vals in groups]

答案 1 :(得分:0)

熊猫解决方案:

j = [
{'flag': True, 'value': 0}, {'flag': True, 'value': 5}, 
{'flag': True, 'value': 10}, {'flag': False, 'value': 15}, 
{'flag': False, 'value': 20}, {'flag': False, 'value': 25}, 
{'flag': False, 'value': 30}, {'flag': False, 'value': 35}, 
{'flag': False, 'value': 40}, {'flag': True, 'value': 45}, 
{'flag': True, 'value': 50}, {'flag': True, 'value': 55}, 
{'flag': True, 'value': 60}, {'flag': False, 'value': 65}, 
{'flag': False, 'value': 70}, {'flag': False, 'value': 75}, 
{'flag': False, 'value': 80}, {'flag': False, 'value': 85}, 
{'flag': True, 'value': 90}, {'flag': True, 'value': 95}]

import pandas as pd

df = pd.DataFrame(j)

df['group'] = df['flag'].ne(df['flag'].shift()).cumsum() # column to groupby 
output = df.groupby("group").apply(lambda x: \
                                   {'flag':x["flag"].tolist()[0], 
                                    'values':(x["value"].min(),x["value"].max())})

output.tolist()

输出:

[{'flag': True, 'values': (0, 10)},
 {'flag': False, 'values': (15, 40)},
 {'flag': True, 'values': (45, 60)},
 {'flag': False, 'values': (65, 85)},
 {'flag': True, 'values': (90, 95)}]

Dataframe看起来像:

    flag    value   group
0   True    0   1
1   True    5   1
2   True    10  1
3   False   15  2
4   False   20  2
5   False   25  2
6   False   30  2
7   False   35  2
8   False   40  2
9   True    45  3
...

答案 2 :(得分:0)

手动解决方案:

FirefoxOptions firefoxOptions = new FirefoxOptions();
    firefoxOptions.setCapability("marionette", true);
    webdriver = new FirefoxDriver(firefoxOptions);