【问题标题】:Grouping algorithm for combinations组合的分组算法
【发布时间】:2013-08-29 03:13:40
【问题描述】:

假设我有一个项目列表,每个项目都由一个简单的结构定义

struct simpleItem
{
    String Category1;
    String Category2;
    ...
    String CategoryN;
}

每个项目都有一系列属于某些类别的值。 在处理列表时,类别数 N 是已知的,并且每个项目具有相同数量的类别,并且每个类别只有一个值,没有重复的项目。 但是,每个列表都可以有不同的类别集。

我正在寻找一种按类别对这些项目进行分组的方法,如果通过组合类别的每个排列将这些组解构为单个项目,我将得到原始组合,没有重复。

一组结果将是:

struct grouped
{
    String[] Category1;
    String[] Category2;
    ...
    String[] CategoryN;
}

示例

为了这个例子,我们将限制为 3 个类别,但可以有 N 个。

类别

动物、眼睛颜色、毛皮

“动物”类别的选择:猫、狗、鼠、马

“眼睛颜色”类别的选择:蓝色、黄色、绿色、红色、橙色

“毛皮”类别的选择:长、短、卷曲

如果列表包含这 3 个类别的所有排列,则最终结果将是

第 1 组:
动物      [猫、狗、鼠、马]
眼睛颜色【蓝、黄、绿、红、橙】
毛皮           [长、短、卷]

如果我有一个子列表,例如:

  1. 猫,蓝,长
  2. 猫,蓝色,短
  3. 狗,蓝,长
  4. 狗,蓝色,短
  5. 狗,青龙
  6. 大鼠,红色,短
  7. 老鼠,蓝色,短

我们称这个列表为 Input (A)

将这些项目分组后,我们最终可能会得到:(可能还有其他可能性)。 分组标准是尽可能少的输出组。

第 1 组:
动物      [猫、     狗]
眼睛颜色 [蓝色           ]
毛皮          [长、短]

第 2 组:
动物      [狗]
眼睛颜色 [绿色]
毛皮           [长]

第 3 组:
动物      [老鼠           ]
眼睛颜色【红、蓝】
毛皮          [短        ]

我们称这些组为输出(B)

如我们所见,通过组合结果组的每个项目,我们将返回到 (A) 中 7 个元素的原始输入列表。

问题

所以,我正在尝试编写一个生成这些组的算法。我正在尝试使用 LINQ 执行此操作,但我也愿意接受其他建议。 关于如何从(A)(B)有什么建议吗?

【问题讨论】:

  • 同一个输入很容易有多个输出。算法是否应该根据某些标准选择“最佳”算法?例如,微不足道的输出将由每个列表项组成一个组(忽略重复项)。
  • 抱歉,我可能没有正确理解您的问题,但这 7 项、7 组中的每一项不都是一个人吗?
  • @kol 好点。标准应该是尽可能少的输出组。我会更新问题以反映这一点。谢谢。

标签: c# algorithm linq


【解决方案1】:
  1. 获取每个输入并将其视为自己的组。
    • 因此,例如,Cat、Blue、Long 成为 [Cat]、[Blue]、[Long] 的组,每个类别只有一个项目。
  2. 遍历列表中的每个组,从第一个开始。将其与列表中的其他组配对。如果它们符合适当的标准,则将这些组对组合成一个组。
    • 合并组的标准是 n-1 个类别的值集是否相同,并且完全一个类别集匹配。如果是这种情况,请创建一个新组,其中 n-1 个相似类别相同,其余类别为集合的交集。
  3. 如果找到匹配项,请停止比较配对并从第一组中的第一项重新开始。 (在此处使用延迟执行可以帮助您,这样您就不必在找到匹配项后立即将组配对。)
  4. 如果您遍历整个集合但没有找到匹配项,那么您就完成了,没有更多的组合可以进行。

所以,看看你的例子。首先,它将第一组和第二组配对。前两个类别集相同,第三个不同,因此可以合并。您现在有一个列表:

  1. [猫]、[蓝色]、[长、短]
  2. [狗]、[蓝]、[长]
  3. [狗]、[蓝色]、[短]
  4. [狗]、[绿]、[长]
  5. [鼠]、[红]、[短]
  6. [老鼠]、[蓝色]、[短]

接下来我们比较(新的)第一组和第二组。第一类和第三类都不匹配,不合并。接下来我们比较第一个和第三个,同样的两个类别不会匹配。第一组不会匹配任何其他组。所以现在我们进入第二组。我们将它与第三个配对。可以合并,因为前两个类别不同:

  1. [猫]、[蓝色]、[长、短]
  2. [狗]、[蓝色]、[长、短]
  3. [狗]、[绿]、[长]
  4. [鼠]、[红]、[短]
  5. [老鼠]、[蓝色]、[短]

现在我们重新开始,将第一组和第二组配对。他们匹配。第一类不同,第二类相同,第三类相同。现在是:

  1. [猫、狗]、[蓝色]、[长、短]
  2. [狗]、[绿]、[长]
  3. [鼠]、[红]、[短]
  4. [老鼠]、[蓝色]、[短]

我们现在将第一个与其他三个进行比较,没有一个会匹配。然后我们将第二个与其他两个进行比较,没有一个会匹配。最后第三个和第四个会匹配,因为只有第二个类别不同:

  1. [猫、狗]、[蓝]、[长、短]
  2. [狗]、[绿]、[长]
  3. [鼠]、[红、蓝]、[短]

最后,我们将遍历所有的组合,没有一个组符合合并条件,我们就完成了。

【讨论】:

  • 感谢您的回答!不过我有点担心性能。我可能有很多输入条目,我担心所有循环和比较都可能是一个问题。我在考虑使用 linq,但我猜 linq 函数会在幕后做几乎相同的事情?
  • @Tigel 您可以使用或不使用 LINQ 来执行此操作。我会大胆尝试实施它,看看你是否真的有问题。这不仅仅是关于您输入的大小的只是。请记住,它可以在找到匹配项后立即停止组合,并且每次找到匹配项时都会缩小数据的大小,可以这么说。如果输入序列中的组大多彼此靠近,实际上有很多组实际上组合在一起,等等,那么情况还不错。您还可以通过利用缓存或其他技术来改进它,同时保持相同的基本方法。
  • 嗨@Mathieu 我正在尝试实现相同的算法,但效率似乎很差。你有什么建议可以进一步优化上述算法吗?
  • 嗨@ocind 我很难记住我一个月做了什么,更不用说 6 年前了。但是我使用了具有大量数据的算法,并且性能是可以接受的。我不知道您使用的是什么语言,但我确实使用了结构而不是类,因为对数百万个对象的 ctor 调用效率不高。
猜你喜欢
  • 1970-01-01
  • 2011-01-31
  • 1970-01-01
  • 2011-08-21
  • 1970-01-01
相关资源
最近更新 更多