用于聚合键包含数字的键值对的算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用于聚合键包含数字的键值对的算法相关的知识,希望对你有一定的参考价值。

我会尽力给出一个完整的问题定义。为了说明这个问题,我将在后面的问题中给出一个例子。您可能希望先跳转到示例并在之后阅读我的问题定义。

问题

我有一张代表键值对的地图。密钥可以以-NUMBER结尾,其中NUMBER是整数。但是,也可能存在不以短划线和数字结尾的键。

领先的-NUMBER之前的关键字也可能包含破折号。

可能有多个键以相同的字符串开头并以不同的数字结尾。

也可能有多个键以不同的字符串开头,也以数字结尾。

大体情况

  1. 所有钥匙都是独一无二
  2. 地图未订购
  3. 密钥的顺序是随机的
  4. 可以安全地假设键中的所有字符串都是大写的
  5. 如果有一个以短划线结尾的键和一个更大的数字n,则保证所有键以相同的字符串开头并以所有数字m结尾,其中1 <m <n存在于地图中。
  6. 以数字结尾的原始密钥是否保留在最终集合中并不重要

专注于解决方案

解决方案不应该严格地关注优化运行时或空间复杂性,而是可读性和可维护性。地图中大约有200个条目,应用程序上预计不会有高流量。

输入:

{
    "FIRST-KEY"   = "FOO",
    "SECOND-KEY-3"= "BAZ",
    "THIRD-KEY-2" = "BAR",
    "SECOND-KEY-1"= "FOO",
    "SECOND-KEY-2"= "BAR",
    "THIRD-KEY-1" = "FOO"
}

预期产出:

{
    "FIRST-KEY" = "FOO",
    "SECOND-KEY"= ["FOO", "BAR", "BAZ"],
    "THIRD-KEY" = ["FOO", "BAR"]
}

或(如果原始密钥保留在结果中):

{
    "FIRST-KEY"   = "FOO",
    "SECOND-KEY-3"= "BAZ",
    "THIRD-KEY-2" = "BAR",
    "SECOND-KEY-1"= "FOO",
    "SECOND-KEY-2"= "BAR",
    "THIRD-KEY-1" = "FOO",
    "FIRST-KEY"   = "FOO",
    "SECOND-KEY"  = ["FOO", "BAR", "BAZ"],
    "THIRD-KEY"   = ["FOO", "BAR"]
}

最后的笔记

我的解决方案必须在ColdFusion中实现。在我的问题开始时我必须将其称为map的输入在ColdFusion中称为struct

您可以在ColdFusion(首选脚本语法)中表达您的答案,但您也可以选择您喜欢的任何其他语言(包括伪代码),只要您不使用我在ColdFusion中无法使用的其他语言的标准库。

答案

如果保证所有数字1 ... n都存在,一个简单的方法就是遍历所有的关键名称。对于每个键,使用正则表达式来提取“组”名称(即FIRST-KEYSECOND-KEY等等)和可选的-NUMBER后缀。

results = {};

for (key in structKeyArray(yourStruct)) {

   keyGroup  = reReplaceNoCase(key, "(.+)-d+$", "1", "ALL");
   insertAt  = reReplaceNoCase(key, "[^d+$]", "", "ALL");
   isSequence = insertAt > 0;

   // ....

如果数字> 0,则设置一个布尔标志,指示当前项是一系列相似键的一部分。然后检查您之前是否处理过当前的“组”。如果没有,请使用空数组初始化它。

    if (isSequence && !results.keyExists( keyGroup )) {
        results[ keyGroup ] = [];
    }

最后,存储当前的“值”。如果当前项是序列的一部分,请将值插入现有数组中。 (由于-NUMBER是顺序的,并且从1开始,它可以用作数组索引,确保以正确的顺序插入值。)否则,只需将其存储为简单值。

    if (isSequence) {
        results[ keyGroup ][ insertAt ] = yourStruct[ key ];
    }
    else {
        results[ keyGroup ] = yourStruct[ key ];
    }

 } // end loop
另一答案

感谢Slack上的ColdFusion社区,我们提出了满足我要求的解决方案:

data = data.reduce(function(acc, k, v) {
    var lastElement = listLast(k, '-');
    if(isNumeric(lastElement)) {
        var newKey = reReplace(k, '-d+$', '');
        // init array if not initialized yet
        if(!acc.keyExists(newKey)) acc[newKey] = [];
        acc[newKey][lastElement] = v;
    }

    // may be put into an else block. This is only in here to attach the original keys in any case
    acc[k] = v;

    return acc;
}, {});

IMO它非常简洁,紧凑和优雅。此外,它主要是自我解释的,可以直观地理解。

这个想法是,整个问题可以归结为一个reduction。对于每个元素,我们查看最后一个“段”(由-分隔),如果它是数字,我们可以为该键构建additoinal数组。

如果有人不同意或有更好的解决方案,我会非常乐意看到它。

最后感谢qazxsw poi的努力,解决方案的积分去了qazxsw poi

以上是关于用于聚合键包含数字的键值对的算法的主要内容,如果未能解决你的问题,请参考以下文章

java问题,我想在java中存储键值对,以便使用,但是键值对的键和值都有重复元素,使用hashmap会产生覆盖。

HashMapHashTableConcurrentHashMap详解

js中往数组对象中添加键值对的方法有哪些?

js中往数组对象中添加键值对的方法有哪些?

算法 合并表记录

从一维条码中读取的键值对的有效压缩和表示