根据单独数组的顺序对数组集合进行排序的最有效方法

时间:2020-06-11 23:54:12

标签: javascript

是的,我知道类似的问题,但是这里并没有涵盖我的用例。

我在寻找降低时间复杂度的方法时遇到了困难

我有两个这样的对象

const people = [
  {
    name: 'Steve',
    id: 1,
    fruitInBasket: 6
  },
  {
    name: 'James',
    id: 2,
    fruitInBasket: 4
  }
]
const homes = [
  {
    id: 1,
    familyMembers: [
      {
        name: 'James',
        id: 2
      },
      {
        name: 'Steve',
        id: 1
      }
    ]
  },
  {
    id: 2,
    familyMembers: [
      {
        name: 'James',
        id: 2
      },
      {
        name: 'Steve',
        id: 1
      }
    ]
  }
]

因此,一个是people的集合,篮子里有很多水果,另一个是homes的集合,每个家庭中的用户与people中的用户相同集合。

现在我想根据fruitInBasket的数量对每个家庭中的用户进行排序,所以我已经完成了

// create an empty table to store the order of the people
let orderTable = {};

// order the people based off the count in fruitInBasket using lodash orderBy
people = orderBy(people, ['fruitInBasket'], ['desc']);

// create the table 
orderTable = people.reduce((acc, item, index) => {
  return {
    ...acc,
    [item.id]: index
  }
}, {});

// order the people in each home based on the order in the `orderTable`
homes.forEach((home) => {
  let members = [];
  home.familyMembers.forEach((member) => {
    let i = orderTable[member.id];
    members[i] = member;
  });
  home.familyMembers = members;
})

因此,您立即可以看到嵌套的for循环-从来都不是理想的..但是我找不到解决该问题的方法。此方法必须整理大量数据,我注意到巨大的性能问题。

任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:2)

这应该是O(N log N)。它的性能瓶颈是一次性的。其他一切只是O(N)迭代。仍然可以进行一些微优化。
生成有序的地图查找表。
只需根据该映射移动数组。

有一个hpc排序库,在基准测试中,它的测量速度比内置JavaScript快10至40倍,可以添加基准以提高性能。

我不确定,但是familyMember表是否对于每个主对象都一样?您不仅可以将相同的familyMember数组复制到每个对象,还是它们具有不同的属性?
每个家庭的额外优化可能是将上表转换为索引到索引的映射,以便将本机级数组索引用于后续排序。

/db/app/oracle/product/11.2.0.3/dbhome_1
const orderMap = Object.fromEntries(people.sort((x,y)=>x.fruitInBasket-y.fruitInBasket).map(({id},i)=>[id,i]))
// O(N)+O(NlogN)

homes.forEach(home=>{
const {familyMembers:fms} = home
const arr = new Array(fms.length)
//may want to prefill to maintain PACKED array: https://v8.dev/blog/elements-kinds#avoid-creating-holes
for(const fm of fms) arr[ orderMap[fm.id] ] = fm
home.familyMembers = arr
})
// map lookup O(N)

console.log(homes)

答案 1 :(得分:1)

您可以过滤和排序:

const people = [
  {
    name: 'Steve',
    id: 1,
    fruitInBasket: 6
  },
  {
    name: 'James',
    id: 2,
    fruitInBasket: 4
  },
  {
    name: 'Cesar',
    id: 3,
    fruitInBasket: 14
  }
]

const homes = [
  {
    id: 1,
    familyMembers: [
      {
        name: 'James',
        id: 2
      },
      {
        name: 'Cesar',
        id: 3
      },
      {
        name: 'Steve',
        id: 1
      }
      
    ]
  },
  {
    id: 2,
    familyMembers: [
      {
        name: 'James',
        id: 2
      },
      {
        name: 'Steve',
        id: 1
      }
    ]
  }
]

homes.forEach(function(home){
  home.familyMembers.sort((a,b)=>people.find(x=>x.id == a.id).fruitInBasket - people.find(x=>x.id == b.id).fruitInBasket)
})

console.log(homes)

说明:

您将遍历房屋:

homes.forEach(function(home){

您将对成员进行排序

.familyMembers.sort((a,b)

要进行排序,您必须获取成员的果实,因此您找到正确的ID,然后采用正确的属性:

people.find(x=>x.id == a.id).fruitInBasket

然后您进行比较:

(a,b)=>people.find(x=>x.id == a.id).fruitInBasket - people.find(x=>x.id == b.id).fruitInBasket

如果您要寻找的是性能,则应更改people结构:

const people = {
  1:  {
    name: 'Steve',
    fruitInBasket: 6
  },
  2: {
    name: 'James',
    fruitInBasket: 4
  }
}

这样,您可以更轻松地获取水果:

people[id].fruits

此外,如果您的“ id”是在某处定义的,则不要在其他地方定义它。您的homes应该如下所示:

const homes = {
  1:  {
    familyMembers: [1, 2, 3]  
  },
  2: {
    familyMembers: [1,2]
  }
}

所以您的算法如下:

const people = {
  1:  {
    name: 'Steve',
    fruitInBasket: 6
  },
  3: {
    name: 'James',
    fruitInBasket: 4
  },
  2: {
    name: 'Cesar',
    fruitInBasket: 9114
  }
}

const homes = {
  1:  {
    familyMembers: [1, 2, 3]  
  },
  2: {
    familyMembers: [1,2]
  }
}

Object.keys(homes).forEach(function(k){
  homes[k].familyMembers.sort((a,b)=>people[a].fruitInBasket - people[b].fruitInBasket)
})

console.log(homes)