根据另一个 id 数组对对象数组进行排序
Sort an array of objects based on another array of ids
我有 2 个数组
a = [2,3,1,4]
b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
如何根据 a
对 b
进行排序?我想要的输出是
c = [{id: 2}, {id: 3}, {id: 1}, {id: 4}]
我更愿意使用 Ramda 或常规 JS。
您可以根据 a
创建 c
,而无需使用 b
:
var a = [2,3,1,4];
var c = [];
for(var i = 0; i < a.length; i++){
c.append({id:a[i]);
}
希望对您有所帮助!
此解决方案使用 Array#sort
和辅助对象 c
作为索引。
{
"1": 2,
"2": 0,
"3": 1,
"4": 3
}
var a = [2, 3, 1, 4],
b = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
c = a.reduce(function (r, a, i) {
r[a] = i;
return r;
}, {});
b.sort(function (x, y) {
return c[x.id] - c[y.id];
});
document.write('<pre>' + JSON.stringify(b, 0, 4) + '</pre>');
对于更大的对象,我建议使用Sorting with map。
或者可能更简单
b.sort(function(obj1,obj2){
return a.indexOf(obj1.id) > a.indexOf(obj2.id)
});
普通javascript,使用Array
(ES2015
标准)的一些方法
var a = [2,3,1,4];
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
var c = [];
a.forEach(el => c.push(b.find(e => e.id == el)));
document.write(JSON.stringify(c, 0, 2));
您可以为 JavaScript 的 Array#sort
方法提供自定义比较函数。
使用自定义比较函数保证排序顺序:
var sortOrder = [2,3,1,4],
items = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
items.sort(function (a, b) {
return sortOrder.indexOf(a.id) - sortOrder.indexOf(b.id);
});
MDN:
- If compareFunction(a, b) returns less than 0, sort a to an index lower than b (i.e. a comes first).
- If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behavior, thus, not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
- If compareFunction(a, b) returns greater than 0, sort b to an index lower than a (i.e. b comes first).
Hitmands 对上述解决方案做出了非常公正的评论:
This approach is O(n2), and would cause performance issues in big sized lists. Better to buiild the dictionary first, so that it stays O(n)
因此,上述解决方案最终可能无法满足您对大量输入的需求。
实施 Hitmands 的建议:
let sortOrder = [2,3,1,4],
items = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const itemPositions = {};
for (const [index, id] of sortOrder.entries()) {
itemPositions[id] = index;
}
items.sort((a, b) => itemPositions[a.id] - itemPositions[b.id]);
使用 Ramda,您必须通过 mapObjIndexed 函数将 b 中的对象映射到它们的索引,然后搜索 a。你可以试试here.
var a = [2,3,1,4];
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
R.find( R.propEq('id', a[0]), b )
R.values(R.mapObjIndexed( (num, key, obj) => R.find( R.propEq('id', a[key]), b ) , b))
Ramda 对这些类型的问题真的很有帮助。
如果数据量很小,我们可以使用一个简单的 reduce function, and indexOf 助手。
// match id of object to required index and insert
var sortInsert = function (acc, cur) {
var toIdx = R.indexOf(cur.id, a);
acc[toIdx] = cur;
return acc;
};
// point-free sort function created
var sort = R.reduce(sortInsert, []);
// execute it now, or later as required
sort(b);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]
这适用于小型(ish)数据集,但 indexOf 通过缩减的每次迭代操作对于大型数据集来说效率低下。
我们可以通过从另一方面解决问题来解决这个问题,让我们对所需的索引使用 groupBy to group our objects by their id, thus creating a dictionary lookup (much better!). We can then simply map 并将它们转换为该位置的相应对象。
下面是使用这种方法的解决方案:
var groupById = R.groupBy(R.prop('id'), b);
var sort = R.map(function (id) {
return groupById[id][0];
});
sort(a);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]
最后,这是另一种解决方案,非常简洁:
R.sortBy(R.pipe(R.prop('id'), R.indexOf(R.__, a)))(b);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]
我喜欢这种将函数与行为组合在一起并将算法与它使用 Ramda 作用的数据分开的方式。您最终会得到非常易读且易于维护的代码。
很好的解决方案。留在这里以备将来使用:)
const sortBy = (array, values, key = 'id') => ((map) => values.reduce((a,i) =>
a.push(map[i]) && a,[]))(array.reduce((a,i) => (a[i[key]] = i) && a, {}));
用法
a = [2,3,1,4]
b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
sortBy(b, a) // [{id: 2}, {id: 3}, {id: 1}, {id:` 4}]
这是一个使用 Ramda 的替代构造,它可能更简洁一些,而且这些函数很容易重新用于其他用途。
const {indexBy, prop, map, flip} = R
const a = [2,3,1,4]
const b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
const toIndexById = indexBy(prop('id'))
const findIndexIn = flip(prop)
const c = map(findIndexIn(toIndexById(b)), a)
console.log(c)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
我将迭代 的解决方案。
这里正确的做法是翻转问题,而不是
"根据 b
给出的顺序排序 a
",
我宁愿 "使用来自 a
" 的数据丰富 b
"
这让您可以将此函数的时间复杂度保持在 O(n)
,
而不是将其提高到 O(n2)
.
const pickById = R.pipe(
R.indexBy(R.prop('id')),
R.flip(R.prop),
);
const enrich = R.useWith(R.map, [pickById, R.identity]);
// =====
const data = [2, 3, 1, 4];
const source = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
console.log(
enrich(source, data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>
使用 ES6 映射和查找
const a = [2,3,1,4];
const b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
// map over a, find it in b and return
const c = a.map((i) => b.find((j) => j.id === i));
我有 2 个数组
a = [2,3,1,4]
b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
如何根据 a
对 b
进行排序?我想要的输出是
c = [{id: 2}, {id: 3}, {id: 1}, {id: 4}]
我更愿意使用 Ramda 或常规 JS。
您可以根据 a
创建 c
,而无需使用 b
:
var a = [2,3,1,4];
var c = [];
for(var i = 0; i < a.length; i++){
c.append({id:a[i]);
}
希望对您有所帮助!
此解决方案使用 Array#sort
和辅助对象 c
作为索引。
{
"1": 2,
"2": 0,
"3": 1,
"4": 3
}
var a = [2, 3, 1, 4],
b = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
c = a.reduce(function (r, a, i) {
r[a] = i;
return r;
}, {});
b.sort(function (x, y) {
return c[x.id] - c[y.id];
});
document.write('<pre>' + JSON.stringify(b, 0, 4) + '</pre>');
对于更大的对象,我建议使用Sorting with map。
或者可能更简单
b.sort(function(obj1,obj2){
return a.indexOf(obj1.id) > a.indexOf(obj2.id)
});
普通javascript,使用Array
(ES2015
标准)的一些方法
var a = [2,3,1,4];
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
var c = [];
a.forEach(el => c.push(b.find(e => e.id == el)));
document.write(JSON.stringify(c, 0, 2));
您可以为 JavaScript 的 Array#sort
方法提供自定义比较函数。
使用自定义比较函数保证排序顺序:
var sortOrder = [2,3,1,4],
items = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
items.sort(function (a, b) {
return sortOrder.indexOf(a.id) - sortOrder.indexOf(b.id);
});
MDN:
- If compareFunction(a, b) returns less than 0, sort a to an index lower than b (i.e. a comes first).
- If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behavior, thus, not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
- If compareFunction(a, b) returns greater than 0, sort b to an index lower than a (i.e. b comes first).
Hitmands 对上述解决方案做出了非常公正的评论:
This approach is O(n2), and would cause performance issues in big sized lists. Better to buiild the dictionary first, so that it stays O(n)
因此,上述解决方案最终可能无法满足您对大量输入的需求。
实施 Hitmands 的建议:
let sortOrder = [2,3,1,4],
items = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const itemPositions = {};
for (const [index, id] of sortOrder.entries()) {
itemPositions[id] = index;
}
items.sort((a, b) => itemPositions[a.id] - itemPositions[b.id]);
使用 Ramda,您必须通过 mapObjIndexed 函数将 b 中的对象映射到它们的索引,然后搜索 a。你可以试试here.
var a = [2,3,1,4];
var b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
R.find( R.propEq('id', a[0]), b )
R.values(R.mapObjIndexed( (num, key, obj) => R.find( R.propEq('id', a[key]), b ) , b))
Ramda 对这些类型的问题真的很有帮助。
如果数据量很小,我们可以使用一个简单的 reduce function, and indexOf 助手。
// match id of object to required index and insert
var sortInsert = function (acc, cur) {
var toIdx = R.indexOf(cur.id, a);
acc[toIdx] = cur;
return acc;
};
// point-free sort function created
var sort = R.reduce(sortInsert, []);
// execute it now, or later as required
sort(b);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]
这适用于小型(ish)数据集,但 indexOf 通过缩减的每次迭代操作对于大型数据集来说效率低下。
我们可以通过从另一方面解决问题来解决这个问题,让我们对所需的索引使用 groupBy to group our objects by their id, thus creating a dictionary lookup (much better!). We can then simply map 并将它们转换为该位置的相应对象。
下面是使用这种方法的解决方案:
var groupById = R.groupBy(R.prop('id'), b);
var sort = R.map(function (id) {
return groupById[id][0];
});
sort(a);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]
最后,这是另一种解决方案,非常简洁:
R.sortBy(R.pipe(R.prop('id'), R.indexOf(R.__, a)))(b);
// [ { id: 2 }, { id: 3 }, { id: 1 }, { id: 4 } ]
我喜欢这种将函数与行为组合在一起并将算法与它使用 Ramda 作用的数据分开的方式。您最终会得到非常易读且易于维护的代码。
很好的解决方案。留在这里以备将来使用:)
const sortBy = (array, values, key = 'id') => ((map) => values.reduce((a,i) =>
a.push(map[i]) && a,[]))(array.reduce((a,i) => (a[i[key]] = i) && a, {}));
用法
a = [2,3,1,4]
b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
sortBy(b, a) // [{id: 2}, {id: 3}, {id: 1}, {id:` 4}]
这是一个使用 Ramda 的替代构造,它可能更简洁一些,而且这些函数很容易重新用于其他用途。
const {indexBy, prop, map, flip} = R
const a = [2,3,1,4]
const b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}]
const toIndexById = indexBy(prop('id'))
const findIndexIn = flip(prop)
const c = map(findIndexIn(toIndexById(b)), a)
console.log(c)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
我将迭代
这里正确的做法是翻转问题,而不是
"根据 b
给出的顺序排序 a
",
我宁愿 "使用来自 a
" 的数据丰富 b
"
这让您可以将此函数的时间复杂度保持在 O(n)
,
而不是将其提高到 O(n2)
.
const pickById = R.pipe(
R.indexBy(R.prop('id')),
R.flip(R.prop),
);
const enrich = R.useWith(R.map, [pickById, R.identity]);
// =====
const data = [2, 3, 1, 4];
const source = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }];
console.log(
enrich(source, data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>
使用 ES6 映射和查找
const a = [2,3,1,4];
const b = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
// map over a, find it in b and return
const c = a.map((i) => b.find((j) => j.id === i));