如何在Javascript中将包含重复值的数组映射到唯一数组?

21

我有以下数组:

var tst = 
[
 {"topicId":1,"subTopicId":1,"topicName":"a","subTopicName":"w"},
 {"topicId":1,"subTopicId":2,"topicName":"b","subTopicName":"x"},
 {"topicId":1,"subTopicId":3,"topicName":"c","subTopicName":"y"},
 {"topicId":2,"subTopicId":4,"topicName":"c","subTopicName":"z"}
]

有没有一种简单的方法可以将它映射到这种数组形式,其中 topicId > id 且 topicName > name:
var t = 
[
  {"id":1,"name":"a"},
  {"id":2,"name":"c"}
]

我使用现代浏览器并且有 _lodash 库,如果这对翻译有帮助的话。注意 tst 数组中将会有大约 100 行数据,因此不需要非常优化的解决方案。简单易维护的方案更加重要。


以下是关于编程的相关内容的翻译:重复的https://dev59.com/uGYq5IYBdhLWcg3wfgnd。 - Wiktor Zychla
哇,我刚刚看了那个链接。有很多代码。我想知道是否有更简单的 Lodash 解决方案。 - user1943020
“topicId > id and topicName > name” 是什么意思?topicName 和 name 都是字符串,它们不能相互大于或小于吧? - xspydr
3个回答

33

最近更新

_.uniqBy 现在更可取

查看完整工作示例

var tst = [
 {"topicId":1,"subTopicId":1,"topicName":"a","subTopicName1":"w"},
 {"topicId":2,"subTopicId":2,"topicName":"b","subTopicName2":"x"},
 {"topicId":3,"subTopicId":3,"topicName":"c","subTopicName3":"y"},
 {"topicId":1,"subTopicId":4,"topicName":"c","subTopicName4":"z"}
];

var result = _.map(_.uniqBy(tst, 'topicId'), function (item) {
    return {
        id: item.topicId,
        name: item.topicName
    };  
});

console.log(result);

传统遗留系统

http://lodash.com/docs#uniq 是一个不错的起点。

_.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');

您的代码应该像这样获取唯一ID的主题
var t = _.uniq(tst, 'topicId');

编辑

我创建了一个jsfiddle

http://jsfiddle.net/q5HNw/

更新

移除了不必要的名称唯一性

http://jsfiddle.net/q5HNw/1/


你能给我一个使用我已有代码的例子吗?当我看你的例子时,我不太确定如何更改字段名称。 - user1943020
每个topicID的topicName始终相同。因此,是否可以通过仅进行一个_.uniq检查来使其更简单? - user1943020
_.uniq(t, 'name') 指令扔掉就行了,我会更新我的回答和 jsfiddle。 - axelduch
这个似乎无法识别唯一的主题名称?至少我的测试失败了。 - Dalorzo
@Melina 我想我误解了你的意思,你必须使用uniq按topicName进行过滤,因为具有id X和名称Y的主题可能具有id W但名称也是Y。 - axelduch

2

我是那些使用原生函数的人之一 :)


var results = tst.reduce(function(res,topic){
var exists = res.some(function(t){ return (t.id === topic.topicId && t.name === topic.topicName);});        
     if (!exists){
        res.push({"id": topic.topicId, "name": topic.topicName});
     }
return res; },[]);

Lodash版本

我不是一个熟练使用Lodash的专家,可能我会尝试像这样做:

var results = _.reduce(tst, function(res, topic){       
    var exists = _.findIndex(res, function(t){
        return (t.id === topic.topicId && t.name === topic.topicName);
    });
    if (exists === -1){
      res.push({"id": topic.topicId, "name": topic.topicName});
    }
    return res; 
},[]);

但是我已经在其他地方使用了lodash。考虑到我只有很少的记录,并且这不是经常需要的,我想知道是否使用lodash会更容易。只是考虑使用lodash可能更容易维护。 - user1943020
@Melina 我已经将原帖翻译成了 lodash。 - Dalorzo

-1

使用 ECMAScript 2015 Array.prototype.find()

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

let tst = [
     {"topicId":1,"subTopicId":1,"topicName":"a","subTopicName":"w"},
     {"topicId":1,"subTopicId":2,"topicName":"b","subTopicName":"x"},
     {"topicId":1,"subTopicId":3,"topicName":"c","subTopicName":"y"},
     {"topicId":2,"subTopicId":4,"topicName":"c","subTopicName":"z"},
];

let t = [];
tst.forEach(obj => {
  // Check if the id already exists in the array 't'
  if (!t.find((self) => self.id === obj.topicId)) {
    // If not, pushes obj to t
    t.push({
      id: obj.topicId,
      name: obj.topicName
    });
  }
});

console.log(t);

您还可以比较多个属性:

let tst = [
         {"topicId":1,"subTopicId":1,"topicName":"a","subTopicName":"w"},
         {"topicId":1,"subTopicId":2,"topicName":"b","subTopicName":"x"},
         {"topicId":1,"subTopicId":3,"topicName":"c","subTopicName":"y"},
         {"topicId":2,"subTopicId":4,"topicName":"c","subTopicName":"z"},
];


let t = [];
tst.forEach(obj => {
  // Check if the 'id' and 'subId' already exist in t 
  if (!t.find((self) => self.id === obj.topicId && self.subId === obj.subTopicId)) {
    // If not, pushes obj to t
    t.push({
      id: obj.topicId,
      subId: obj.subTopicId,
      name: obj.topicName
    });
  }
});

console.log(t);


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