提问人:InterstellarX 提问时间:4/21/2022 最后编辑:customcommanderInterstellarX 更新时间:4/23/2022 访问量:3366
检查两个数组是否具有具有相同属性的对象
Check if two arrays have an object with the same property
问:
我的目标是:比较两个对象,找出是否有 1 个或多个共同点。如果有 1 个或多个共同点,则返回 否则(没有共同点),返回 。true
false
当前问题: 我正在尝试将该方法与 API 中的 1 个对象和 1 个本地对象一起使用,但有点困惑为什么它不起作用......有什么想法吗?它应该返回 true,因为 John 在两个对象中,但它返回 false 🙃.some()
代码示例:在此示例中,它应该返回,因为 John 是一个既是对象 1 (result1) 又是对象 2 (result 2) 的名称。但是,它返回 .true
false
有没有人能够帮助我理解我在这里做错了什么?
var result1 = [
{id:1, name:'Sandra', type:'user', username:'sandra'},
{id:2, name:'John', type:'admin', username:'johnny2'},
{id:3, name:'Peter', type:'user', username:'pete'},
{id:4, name:'Bobby', type:'user', username:'be_bob'}
];
var result2 = [
{id:2, name:'John', email:'[email protected]'},
{id:4, name:'Bobby', email:'[email protected]'}
];
const hasSimilarElement = result1.some((item) => item.name === result2.name);
console.log(hasSimilarElement);
答:
从上面的评论...
“OP 需要在
result2
中找到具有相等item.name
值result1
的项目,而不是直接比较result2
的不存在(因此未定义
)的名称
属性。”
或者,正如 3limin4t0r 正确建议的那样,一个人可以再次将
find
换成另一个。
const result1 = [
{ id: 1, name: 'Sandra', type: 'user', username: 'sandra' },
{ id: 2, name: 'John', type: 'admin', username: 'johnny2' },
{ id: 3, name: 'Peter', type: 'user', username: 'pete' },
{ id: 4, name: 'Bobby', type: 'user', username: 'be_bob' },
];
const result2 = [
{ id: 5, name: 'Lea', email: '[email protected]' },
{ id: 2, name: 'John', email: '[email protected]' },
];
const result3 = [
{ id: 5, name: 'Lea', email: '[email protected]' },
];
const result4 = [];
console.log(
'similar elements within `result1` and `result2` ..?',
result1.some(itemA =>
result2.some(itemB => itemB.name === itemA.name)
)
);
console.log(
'similar elements within `result1` and `result3` ..?',
result1.some(itemA =>
result3.some(itemB => itemB.name === itemA.name)
)
);
console.log(
'similar elements within `result1` and `result4` ..?',
result1.some(itemA =>
result4.some(itemB => itemB.name === itemA.name)
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
在下一次迭代中,原因之一可能会提出一个通用实现的函数,该函数允许自由选择被比较的属性名称。
实现函数还提供了摆脱两个嵌套迭代的机会(尽管原因提前退出以进行成功的比较)。some
some
在这里,人们将从较短的数组构建一个(属性名称)特定的值索引(单个迭代任务),其中,在迭代较长的数组时,将查找(不迭代)项目相似性的特定值。key
key
function hasSimilarItemsByKey(key, arrA, arrB) {
const [
// the shorter array will be the base
// for a `key` specific value index.
lookupArray,
// the longer array will be iterated
// and have its item `key` specific
// values looked up at a value index.
targetArray,
] = [
arrA,
arrB,
].sort((a, b) => a.length - b.length);
// create the object based value index
// (from the shorter array).
const valueIndex = lookupArray
.reduce((lookup, item) => {
const value = item[key];
lookup[value] ??= value;
return lookup;
}, Object.create(null)); // A `prototype`-less object. Thus,
// using the `in` operator is safe.
return targetArray.some(item => item[key] in valueIndex);
}
const result1 = [
{ id: 1, name: 'Sandra', type: 'user', username: 'sandra' },
{ id: 2, name: 'John', type: 'admin', username: 'johnny2' },
{ id: 3, name: 'Peter', type: 'user', username: 'pete' },
{ id: 4, name: 'Bobby', type: 'user', username: 'be_bob' },
];
const result2 = [
{ id: 5, name: 'Lea', email: '[email protected]' },
{ id: 2, name: 'John', email: '[email protected]' },
];
const result3 = [
// Attention,
// A matching `id` and a non matching `name`.
{ id: 1, name: 'Lea', email: '[email protected]' },
];
const result4 = [];
console.log(
'similar elements within `result1` and `result2`\n',
'...by `name`..?', hasSimilarItemsByKey('name', result1, result2),
'...by `id`..?', hasSimilarItemsByKey('id', result1, result2),
);
console.log(
'similar elements within `result1` and `result3`\n',
'...by `name`..?', hasSimilarItemsByKey('name', result1, result3),
'...by `id`..?', hasSimilarItemsByKey('id', result1, result3),
);
console.log(
'similar elements within `result1` and `result4`\n',
'...by `name`..?', hasSimilarItemsByKey('name', result1, result4),
'...by `id`..?', hasSimilarItemsByKey('id', result1, result4),
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
评论
Array.prototype.some() some() 方法测试数组中是否至少有一个元素通过了由提供的函数实现的测试。
在您的示例中,您尝试比较 2 个对象数组。你有 false,因为 result2.name 未定义,你可能需要指定特定元素的索引,例如 result2[0].name
如果您想将 2 个数组与一些数组进行比较,您还需要遍历 result2 项目。你可以像这样使用somehting:
var result1 = [
{id:1, name:'Sandra', type:'user', username:'sandra'},
{id:2, name:'John', type:'admin', username:'johnny2'},
{id:3, name:'Peter', type:'user', username:'pete'},
{id:4, name:'Bobby', type:'user', username:'be_bob'}
];
var result2 = [
{id:2, name:'John', email:'[email protected]'},
{id:4, name:'Bobby', email:'[email protected]'}
];
const hasSimilarElement = result2.filter((item1) => !result1.some(item2 => item1.name === item2.name ));
console.log(hasSimilarElement);
代码失败的原因是您试图在 result1 Array 的元素中找到 a 的匹配项name
result2.name
但是,也是一个 ,数组没有恰好是与您正在搜索的元素匹配的所有元素 - 这不是它的工作原理result2
Array
.name
.name
您需要遍历两个数组以查找匹配项
var result1 = [
{id:1, name:'Sandra', type:'user', username:'sandra'},
{id:2, name:'John', type:'admin', username:'johnny2'},
{id:3, name:'Peter', type:'user', username:'pete'},
{id:4, name:'Bobby', type:'user', username:'be_bob'}
];
var result2 = [
{id:2, name:'John', email:'[email protected]'},
{id:4, name:'Bobby', email:'[email protected]'}
];
const hasSimilarElement = result1.some((item) => result2.some(item2 => item.name === item2.name));
console.log(hasSimilarElement);
.as-console-wrapper { min-height: 100%!important; top: 0; }
然而,对于非常大的结果集,这是低效的 - 我不是“大 O 符号专家,但我相信这将是 O(n2) - 你可能会比较 * 次result1.length
result2.length
对于这个简单的例子,你可以只从两个结果中提取,并创建一个...如果大小小于组合结果 s,则表示存在重复项.name
Set
Set
.length
在这里,您将对每个结果进行一次迭代 - 如果两个集合都有 1000 个元素,则为 2,000 次迭代,而使用上面的 naïve 方法则为 1,000,000 次
var result1 = [
{id:1, name:'Sandra', type:'user', username:'sandra'},
{id:2, name:'John', type:'admin', username:'johnny2'},
{id:3, name:'Peter', type:'user', username:'pete'},
{id:4, name:'Bobby', type:'user', username:'be_bob'}
];
var result2 = [
{id:2, name:'John', email:'[email protected]'},
{id:4, name:'Bobby', email:'[email protected]'}
];
const hasSimilarElement = new Set([...result1, ...result2].map(({name}) => name)).size < result1.length + result2.length
console.log(hasSimilarElement);
.as-console-wrapper { min-height: 100%!important; top: 0; }
但是,如果其中一个结果中有重复的名称,则存在缺陷,这将无法按预期工作
在这里,每个集合迭代两次 - 但是,给定 2 x 1,000 个长结果,4,000 次迭代仍然优于 1,000,000 次
var result1 = [
{id:1, name:'Sandra', type:'user', username:'sandra'},
{id:2, name:'John', type:'admin', username:'johnny2'},
{id:3, name:'Peter', type:'user', username:'pete'},
{id:4, name:'Bobby', type:'user', username:'be_bob'}
];
var result2 = [
{id:2, name:'John', email:'[email protected]'},
{id:4, name:'Bobby', email:'[email protected]'}
];
const set1 = new Set(result1.map(({name}) => name));
const set2 = new Set(result2.map(({name}) => name));
const both = new Set([...set1, ...set2]);
const hasSimilarElement = both.size < set1.size + set2.size;
console.log(hasSimilarElement);
.as-console-wrapper { min-height: 100%!important; top: 0; }
评论
some()
const hasSimilarElement = result1.some(({name}) => set2.has(name))
set1
both
您可以创建一个函数,该函数将一个函数用于查找,然后是两个数组 &:f
xs
ys
const checkBy = f => (xs, ys) => {
let [long, short] = xs.length > ys.length ? [xs, ys] : [ys, xs];
short = new Set(short.map(f));
return long.some(x => short.has(f(x)));
};
然后:
const checkByName = checkBy(x => x.name);
checkByName( [ {id: 1, name:'Sandra', type: 'user', username: 'sandra'}
, {id: 2, name: 'John', type: 'admin', username: 'johnny2'}
, {id: 3, name: 'Peter', type: 'user', username: 'pete'}
, {id: 4, name: 'Bobby', type: 'user', username: 'be_bob'}]
, [ {id: 2, name: 'John', email: '[email protected]'}
, {id: 4, name: 'Bobby', email: '[email protected]'}]);
//=> true
checkByName( [ {id: 1, name:'Sandra', type: 'user', username: 'sandra'}
, {id: 2, name: 'John', type: 'admin', username: 'johnny2'}
, {id: 3, name: 'Peter', type: 'user', username: 'pete'}
, {id: 4, name: 'Bobby', type: 'user', username: 'be_bob'}]
, [ {id: 2, name: 'xxxx', email: '[email protected]'}
, {id: 4, name: 'yyyyy', email: '[email protected]'}]);
//=> false
评论
const overlap = (f) => (xs, ys, ks = new Set (xs .map (f))) => ys .some (y => ks .has (f (y)))
f
我会将 customcommander 建议的技术用于您的确切场景,以及您可以从对象中提取唯一键作为基元类型的任何位置。(这里是字符串,所以可以工作。name
如果你需要更通用的东西,那么你可以提供一个函数来判断两个元素是否相等,并像这样使用它:
const overlap = (equal) => (xs, ys) =>
xs .some (x => ys .some (y => equal (x, y)))
const result1 = [{id:1, name:'Sandra', type:'user', username:'sandra'}, {id:2, name:'John', type:'admin', username:'johnny2'}, {id:3, name:'Peter', type:'user', username:'pete'}, {id:4, name:'Bobby', type:'user', username:'be_bob'}]
const result2 = [{id:2, name:'John', email:'[email protected]'}, {id:4, name:'Bobby', email:'[email protected]'}]
console .log (overlap ((x, y) => x .name == y .name) (result1, result2))
在可以生成唯一键的情况下,效率较低,但它更通用。您甚至可以将它用于两个数组,其中两个数组具有具有不同结构的对象,例如传递 。(x, y) => x .id == y .primaryKey
评论
result2.name
result1.some((item) => result2.some(item2 => item.name === item2.name));
.some()
result2.name
undefined
name
找到一个
值相等的项 within ,而不是直接比较一个不存在的(因此)属性。item.name
result1
result2
undefined
name
result2