【问题标题】:How to perform the following ordered subset element test in Python?如何在 Python 中执行以下有序子集元素测试?
【发布时间】:2016-02-06 23:07:32
【问题描述】:

我有一个字典(称为 dict),其键是表示特征名称的字符串,其值是表示每个特征计数的浮点数。

这是我的字典(dict)的一个例子:

{'11268-238-1028': 2.0, '1028': 10.0, '10295': 2.0, '1781': 2.0, '11268-238': 3.0, '6967-167': 1.0, '9742 -232-788': 1.0, '8542': 4.0, '238-1028': 5.0, '1028-122': 1.0}

在此示例中,“10295”被视为一度特征,“6967-167”被视为二度特征,“9742-232-788”是三度特征。如果我们有“x-x-x-x-x-x-x”,那么它将是一个七度特征。换句话说,对于任何 n 度特征,该特征具有 (n-1) 个破折号 ('-')。

'11268-238-1028': 2.0 表示 3 度特征 '11268-238-1028' 的计数为 2。然后我们看到 '11268-238': 3.0 表示 '11268-238 ' 出现 3 次。但是,这是一些重复计数问题,因为在 '11268-238' 的 3 次出现中,其中 2 次实际上是由于 '11268-238-1028' 的出现。因此,我们要将'11268-238'的计数改为它的真实计数,即3-2 = 1。

同样,“238-1028”的实际计数不是 5,因为“238-1028”是“11268-238-1028”的一部分,而“11268-238-1028”的计数为 2。所以,“238-1028”的实际计数应该是(5-2 = 3)。

另一个示例是特征“1028”,其实际计数不应为 10。“1028”是 3 度特征“11268-238-1028”的一部分,其计数为 2。“1028”也是计数为 5 的 2 度特征“238-1028”的一部分。“1028”也是计数为 1 的 2 度特征“1028-122”的一部分。因此,1-学位特征“1028”应该是(10-2-5-1 = 2)。

我应该使用什么样的算法来解决这个问题?

我考虑将每个键转换为由破折号分割的一组 1 度特征,然后对每个集合,针对所有其他长度更长的集合进行子集成员资格测试。但是, set 存储无序元素,但我关心顺序。例如,特征 '11268-238-1028' 转换为集合将是 (['11268', '238', '1028']);转换为 set 的另一个特征“11268-1028”将是 (['11268', '1028'])。如果我对这两个特征集执行子集测试,我会得出结论,(['11268', '1028']) 是 (['11268', '238', '1028']) 的子集。但是,特征“11268-1028”不是特征“11268-238-1028”的子集,因为在“11268”和“1028”之间,还有另一个“238”,即顺序应该很重要。

那我该如何解决这个问题呢?

非常感谢!

【问题讨论】:

  • 你试过了吗?
  • 不转换为set,而是拆分为像l='11268-238-1028'和l.split('-')这样的列表并连续比较
  • 你甚至不需要这样做......
  • 或检查是否为子串

标签: python python-2.7 dictionary set subset


【解决方案1】:

把你的问题分解成更小的不太复杂的问题

首先让我们编写一个辅助函数来实际调整我们的数据字典

# this assumes we have one big feature (ie 3) and several smaller features(ie 2&1)
def adjust_data(big_feature,smaller_features,data):
    for feature in smaller_features:
        if feature.count("-") == big_feature.count("-"):
           continue # skip any features that are the same size as our target
        #3 cases for a sub feature it starts with ends with or is contained
        # we use delimiters to eliminate partial matches
        does_start = big_feature.startswith(feature+"-") 
        does_end = bigfeature.endswith("-"+feature) 
        does_contain = "-"+feature+"-" in big_feature
        if does_start or does_end or does_contain :
            # one of our cases match so this is a sub feature of our big feature
            data[feature] -= data[big_feature]

现在在处理这个之前,我们需要组织我们的数据,以便对其进行适当的排序。

 sorted_keys = sorted(my_data_dict.keys(),
                      key=lambda key:key.count("-"), 
                      reversed=True) #we want bigger features on top

现在只需遍历我们的排序 data_list

  for i,key in enumerate(sorted_keys,1):
      adjust_data(key,sorted_keys[i:],my_data_dict)

这只是蛮力,所以它不会那么快,但它会完成工作

【讨论】:

    【解决方案2】:

    在第一次创建字典时防止重复计算应该比以后撤消它容易得多。

    但是假设 dict 不能被重新创建。这是一个解决方案。它并不假设对于每个更高程度的特征,每个程度都保证有一个较低程度的对应物(也就是说,对于特征 A1-A2-...-An,您可能会缺少 A1、A1-A2 中的任何一个等,直到 A1-A2-...-An-1)。如果这个假设真的成立,一些try-except 可以被简化掉。

    def undo_double_counting(d):
        sorted_features = sorted(d, key=lambda f: f.count('-'), reverse=True)
        for f in sorted_features:
            if '-' not in f:
                return d
            feature_below, _ = f.rsplit('-', 1)
            while True:
                try:
                    d[feature_below] -= d[f]
                except KeyError:
                    # if the feature one degree below isn't actually in d,
                    # we keep trying lower degrees until we know that we
                    # can't go lower any more (by hitting ValueError)
                    try:
                        feature_below, _ = feature_below.rsplit('-', 1)
                    except ValueError:
                        break
                else:
                    break
        # if there are no degree-1 features in d, return here
        return d
    

    在你的数据上尝试一下(顺便说一句,为什么是浮点数,而不是整数?):

    {'1028': 9.0,
     '1028-122': 1.0,
     '10295': 2.0,
     '11268-238': 1.0,
     '11268-238-1028': 2.0,
     '1781': 2.0,
     '238-1028': 5.0,
     '6967-167': 1.0,
     '8542': 4.0,
     '9742-232-788': 1.0}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-30
      • 2023-01-09
      • 2011-09-24
      • 1970-01-01
      • 2016-08-27
      • 2021-01-13
      相关资源
      最近更新 更多