javascript通过特定的对象属性在对象数组中查找对象

时间:2016-04-06 12:44:18

标签: javascript arrays sorting typescript

我有一个像这样的线程对象数组

threadlist:Thread[]= [thread{id:1},thread{id:2},thread{id:3},...]

如果用户有一个特定的书签线程,我也会在下面的用户对象中有一个ThreadRelation数组来存储。 请注意,Thread中的id与它在数组中的位置不匹配。

user{
  user_id:number,...(some other user typical properties)
  threadRelations:ThreadRelation[]=[
  threadRelation{
    id:2,//relates to id property of a Thread object
    isBookmarked:true
  },
  threadRelation{
    id:18,
    isBookmarked:true
  },..
]}

我想创建一个函数,该函数返回一个只包含用户书签线程的数组。我可以使用两个for循环和if语句实现这一点,但我不认为它有效.. 是否有一些方法可以直接在数组中找到该特定对象?

updateBookmarkedList(){
      for (var i = 0; i < this.activeUser.threadsRelation.length; i++){
        if ( this.activeUser.threadsRelation[i].bookmarked == true){
          var searchId = this.activeUser.threadsRelation[i].id;
          for (var j = 0; j < this.threadlist.length; j++){
            if (this.threadlist[j].id == searchId){
              this.userBookmarkedList.push(this.threadlist[j])
            }
          }
        }
      }
  }

谢谢!

3 个答案:

答案 0 :(得分:1)

使用Array.prototype.filter,您只能保留已添加书签的线程关系。从此筛选列表中,您可以基于id条件构建线程列表。

var threads = [
  { id: 1 },
  { id: 2 },
  { id: 3 }
];

var users = [{
  user_id: 1,
  threadRelations: [
    { id: 2,  isBookmarked: true },
    { id: 18, isBookmarked: true }
  ]
}];

var userBookmarkedList = updateBookmarkedList(users[0], threads);
document.body.innerHTML = '<pre>Threads -> ' + JSON.stringify(userBookmarkedList, null, 2) + '</pre>';

function updateBookmarkedList(user, threads) {
  return user.threadRelations.filter(function(threadRelation) {
    return threadRelation.isBookmarked === true;
  }).reduce(function(list, threadRelation) {
    return list.concat(threads.filter(function(thread) {
      return thread.id === threadRelation.id;
    }));
  }, []);
}

您还可以创建地图,以提高查找效果。

var threads = [
  { id: 1 },
  { id: 2 },
  { id: 3 }
];

var users = [{
  user_id: 1,
  threadRelations: [
    { id: 2,  isBookmarked: true },
    { id: 18, isBookmarked: true }
  ]
}];

var threadMap           = mapBy(threads, 'id');
var userBookmarkedList  = retrieveBookmarkedThreads(users[0], threadMap);
document.body.innerHTML = '<pre>Threads -> ' + JSON.stringify(userBookmarkedList, null, 2) + '</pre>';

function mapBy(list, key) {
  return list.reduce(function(map, item) {
    map[item[key]] = item;
    return map;
  }, {});
}

function retrieveBookmarkedThreads(user, threadMap) {
  return user.threadRelations.filter(function(threadRelation) {
    return threadRelation.isBookmarked === true;
  }).reduce(function(list, threadRelation) {
    return (function(thread) {
      return thread != null ? list.concat(thread) : list;
    }(threadMap[threadRelation.id]));
  }, []);
}

答案 1 :(得分:1)

为什么不按照他们的ID保留“线程”的地图?

从数组创建地图:

var threadsById = new Map(threads.map(t => [t.id, t]));

获取是否存在threadid:

if (threadsById.has(threadRelation.id)) {
  ...
}

通过id获取线程:

var currentThread = threadsById.get(threadRelation.id);

答案 2 :(得分:1)

如果Thread.id是唯一标识符,那么您真的应该使用Map而不是没有键的Array个对象。没有键,你将不得不迭代数组而没有其他选择。

在迭代Array时,尝试使用内置的迭代方法,如forEach。它们比循环更有效,看起来更整洁。

为了补充@Tamas-Hegedus's answer using ES6 iterator feature,我使用当前版本的JavaScript创建了一个JSFiddle来制作“数组地图”,如果Map不是Thread.id,则可以将其替换为Web Api 2数字。

请参阅JSFiddle