【问题标题】:How to do "GROUP BY" mathematically?如何在数学上做“GROUP BY”?
【发布时间】:2012-04-02 17:41:42
【问题描述】:

我有一个键值对的数据结构,我想实现“GROUP BY”值。 键和值都是字符串。

所以我所做的就是给每个值(字符串)一个唯一的“素数”。然后对于每个键,我存储了与特定键具有的不同值相关联的所有素数的乘法。 因此,如果键“Anirudh”具有值“x”、“y”、“z”,那么我也存储数字 M(Key) = 2*3*5 = 30。 稍后,如果我想按特定值“x”(比如说)进行分组,那么我只需遍历所有键,然后将 M(键)除以与“x”关联的素数。然后我检查余数是否为 0,如果为零,则该特定“键”是值“x”的 group by 的一部分。

我知道这是最奇怪的做法。有些人对键值对进行排序(按值排序)。我还可以创建另一个已经按“值”分组的表(哈希表)。所以我想知道比我更好的方法(肯定有很多)。在我的方法中,随着特定键的唯一值数量增加,素数的乘积也会增加(呈指数增长)。

【问题讨论】:

  • 这是一个 SQL 问题吗?您有“键/值对的数据结构”。那是数据库表吗?你想要什么样的输出?它与 SQL GROUP BY 有什么不同吗?
  • 它实际上不是数据库表。我认为它是一个逻辑数据结构。是的!它与“SQL GROUP BY”相同。所以我正在寻找一种独立于 SQL 提供的解决方案,更具体地说是一种 GROUP BY 算法。

标签: sql database group-by grouping key-value


【解决方案1】:

您的方法将始终执行 O(n) 来查找组成员,因为您必须遍历集合的所有元素以查找属于目标组的元素。如果您有许多元素,您的方法也可能会溢出常见的整数边界(32 位、64 位),因为您可能会将大量素数相乘以形成您的密钥。

您会发现按照这种方法使用位掩码跟踪组成员身份会更有效,当然也更可预测。如果您有 16 个组,则可以使用位掩码用 16 位短表示。按照您的建议使用素数,您需要一个具有足够位数的整数来保存数字 32589158477190044730(前 16 个素数相乘),这需要 65 位。​​

其他分组方法也是第一次迭代的 O(n) (毕竟,每个元素必须至少测试一次组成员身份)。但是,如果您倾向于重复相同的组检查,那么您引用的其他方法(例如,为每个目标组保留一个列表或哈希表)效率更高,因为后续的组成员资格测试是 O(1)。

所以直接回答你的问题:

  • 如果对组成员身份有多个查询(重复某些组),则任何存储组(包括您在问题中建议的组)的解决方案都将比您的方法执行得更好。
  • 如果没有重复查询组成员身份,则存储组成员身份没有任何好处

鉴于您的问题很可能重复查询:

  • 如果您想交换内存以获得更快的速度,请使用以组 ID 为键的列表等结构来存储组成员身份。
  • 如果您想以速度换取使用更少的内存,请使用适当宽的位数组来存储组成员资格。

【讨论】:

  • 感谢您的建议 Eric,在浏览了我的用例后,我发现“使用以组 ID 为关键字的列表之类的结构来存储组成员身份”非常合适。将您的答案标记为正确的。
【解决方案2】:

如果不知道这里要问什么,但这听起来与位向量或 2 的幂和相似(但计算量更大)。第一个值是“1”,第二个是“2”,第三个是“4”等等。如果你得到“7”,你知道它是“第一”+“第二”+“第三”。

【讨论】:

  • 因此,根据您的解决方案,我将保存“2^0 + 2^1 + 2^2”,因为每个值都有一个数字“2^something”。然后要知道一个特定的值是否映射到一个特定的键,我会做 SUM(key) - 2^something(for that value)。然后我必须检查减法结果是否以 2 的幂的形式存在。如果是,则“键,值”的映射存在,否则存在。但正如您之前所说,它的计算成本很高。无论如何,感谢您的解决方案。
  • 您只需要使用位掩码和按位与来进行测试。如果要查找第 1 组和第 3 组中的内容,则二进制掩码为 00000101,即 0x7。测试将是if (key & 0x7 == 0x7) { /* belongs to both groups */ }
猜你喜欢
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-02
  • 1970-01-01
  • 2011-03-28
  • 2016-10-15
相关资源
最近更新 更多