获取重复元素的数组索引

13

在JavaScript数组中,如何获取重复字符串的索引?

示例:

MyArray = ["abc","def","abc"]; //----> return 0,2("abc");

另一个例子:

My Array = ["abc","def","abc","xyz","def","abc"] 
//----> return 0,2,5("abc") and 1,4("def");

我不知道怎么做这个。 非常感谢你的帮助!


2
遍历并收集,真的不难。不要害怕使用循环。 - Yoshi
"0,2,5(“abc”)和1,4(“def”)"不是有效的返回格式,我可以想到很多细节如何返回它。你应该更明确地说明你想要返回什么内容。 - Ingo Bürk
哦,抱歉,("abc")和("def")只是返回值的细节。我只想返回0、2、5和1、4。 - qwertyuiop
你不能返回 0,2,5 1,4,除非将它们打包成对象,就像我的答案一样。你只能返回类似于 0,1,2,4,5 这样的东西,这样就无法确定它们属于哪个条目或哪个条目包含了多少次。 - Ingo Bürk
另外,还可以使用迭代器模式之类的方式进行添加。但是这肯定不是你想要的。这正是我在第一条评论中所说的:如果你没有指定有效的返回格式,那么有很多方法可以做到这一点。 - Ingo Bürk
3个回答

23
< p >< em >更新于2022年1月:现在已经不是2013年了,很多事情都发生了变化。我不建议修改原型,也不认为本答案的方法是“最好的”,因为它需要对数组进行多次迭代。

以下是原始答案的更新版本,保留其精神和原始答案。

function getDuplicates<T>(input: T[]): Map<T, number[]> {
    return input.reduce((output, element, idx) => {
        const recordedDuplicates = output.get(element);
        if (recordedDuplicates) {
            output.set(element, [...recordedDuplicates, idx]);
        } else if (input.lastIndexOf(element) !== idx) {
            output.set(element, [idx]);
        }

        return output;
    }, new Map<T, number[]>());
}

另一种方法:

Array.prototype.getDuplicates = function () {
    var duplicates = {};
    for (var i = 0; i < this.length; i++) {
        if(duplicates.hasOwnProperty(this[i])) {
            duplicates[this[i]].push(i);
        } else if (this.lastIndexOf(this[i]) !== i) {
            duplicates[this[i]] = [i];
        }
    }

    return duplicates;
};

它返回一个对象,其中键为重复的条目,而值是其索引的数组,即:
["abc","def","abc"].getDuplicates() -> { "abc": [0, 2] }

2
想法:不要在每次迭代中使用indexOflastIndexOf,而是首先检查元素是否已经存在于duplicates中。如果是,则可以直接将索引推送到数组中。这样可以节省一些线性搜索时间,甚至可以完全省略indexOf(只需与i进行比较)。否则,使用lastIndexOf是一个不错的方法! - Felix Kling
我不知道为什么它不起作用...结果是[对象对象]...而且我不需要返回{"abc" : [0, 2]},只需要返回[0, 2]... - qwertyuiop
如果你只是这样输出,你会得到[object Object]。它是一个对象,你必须查看它的属性!而且不,你没有说你只想要[0,2]。这也没有意义,因为你的第二个例子呢?你怎么分离不同条目的重复索引? - Ingo Bürk
@user2695834:对象的默认字符串表示形式是"[object Object]"。因此,如果您使用alert或将其与字符串连接,那就是您得到的结果。然后,您可以进一步处理该对象。您说您只需要[0,2],所以只需迭代该对象并获取该值即可!我假设您具有某些JavaScript基础知识。如果没有,我鼓励您阅读教程,例如http://eloquentjavascript.net/。还要查看我的答案中的链接。 - Felix Kling
1
@Felix Kling:非常感谢!现在它能用了!抱歉之前的评论,因为我只有基本的JavaScript知识。再次感谢Ingo Burk和Felix Kling!你们救了我!:) - qwertyuiop
1
完成了,我想。我是新来的。 - qwertyuiop

4
另一种不太复杂的方法:
遍历整个数组并跟踪每个元素的索引。为此,我们需要一个“字符串 -> 位置”的映射。对象是通常用于此目的的数据类型。键是数组的元素,值是数组中每个元素的索引/位置的数组。
var map = {};

for (var i = 0; i < arr.length; i++) {
    var element = arr[i];  // arr[i] is the element in the array at position i

    // if we haven't seen the element yet, 
    // we have to create a new entry in the map
    if (!map[element]) {
        map[element] = [i];
    }
    else {
       // otherwise append to the existing array
        map[element].push(i);
    }
    // the whole if - else statement can be shortend to
    // (map[element] || (map[element] = [])).push(i)
}

现在您可以遍历该映射并删除所有条目,其中数组值的长度为1。这些是仅在数组中出现一次的元素:
for (var element in map) {
    if (map[element].length === 1) {
        delete map[element];
    }
}

现在 map 包含一个将数组中所有重复元素映射为 string -> positions 的对象。例如,如果你的数组是 ["abc","def","abc","xyz","def","abc"],那么 map 就是一个形如下面的对象:
var map = {
    'abc': [0,2,5],
    'def': [1,4]
};

而且您可以按照任何您喜欢的方式进一步处理它。


更多阅读:


点赞的原因之一是为了您的510k,太棒了。 - Mark

0

这涉及到高效地查找索引:

var inputArray = [1, 2, 3, 4, 5, 6, 6, 7, 8, 9];
var encounteredIndices = {};

for(var i = 0; i < inputArray.length; i++)
  if (encounteredIndices[inputArray[i]])
    console.log(i); // Or add to some array if you wish
  else
    encounteredIndices[inputArray[i]] = 1;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接