这是我的目标:比较两个对象并找出是否有1个或多个相同的项。如果有1个或多个共有项,则返回true
,否则(无共有项),返回false
。
当前问题:我试图使用.some()
方法与1对象从API和1对象是本地的,但有点困惑为什么它不工作…什么好主意吗?它应该返回true,因为John在两个对象中都有,但是它返回false🙃
代码示例:在这个示例中,它应该返回true
,因为John是对象1 (result1)和对象2 (result 2)的名称。然而,它返回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:'johnny@example.com'},
{id:4, name:'Bobby', email:'bobby@example.com'}
];
const hasSimilarElement = result1.some((item) => item.name === result2.name);
console.log(hasSimilarElement);
您可以创建一个函数,该函数接受一个函数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: 'johnny@example.com'}
, {id: 4, name: 'Bobby', email: 'bobby@example.com'}]);
//=> 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: 'johnny@example.com'}
, {id: 4, name: 'yyyyy', email: 'bobby@example.com'}]);
//=> false
我将使用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:'johnny@example.com'}, {id:4, name:'Bobby', email:'bobby@example.com'}]
console .log (overlap ((x, y) => x .name == y .name) (result1, result2))
在可以生成唯一键的情况下效率较低,但它更通用。您甚至可以将它用于两个数组,其中两个数组具有不同结构的对象,例如传递(x, y) => x .id == y .primaryKey
。
Array.prototype.some()some()方法测试数组中是否至少有一个元素通过所提供的函数实现的测试。
在您的示例中,您正在尝试比较两个对象数组。如果result2.name未定义,则可能需要指定特定元素的索引,例如result2[0].name
如果你想比较两个数组与一些你需要迭代通过result2项目以及。你可以这样写:
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:'johnny@example.com'},
{id:4, name:'Bobby', email:'bobby@example.com'}
];
const hasSimilarElement = result2.filter((item1) => !result1.some(item2 => item1.name === item2.name ));
console.log(hasSimilarElement);
代码失败的原因是您试图在result1 Array的元素中找到name
与result2.name
的匹配
然而,result2
也是一个Array
,数组没有一个.name
恰好是所有的元素.name
s,以某种方式匹配你正在搜索的-这不是它的工作方式
你需要迭代两个数组来寻找匹配
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:'johnny@example.com'},
{id:4, name:'Bobby', email:'bobby@example.com'}
];
const hasSimilarElement = result1.some((item) => result2.some(item2 => item.name === item2.name));
console.log(hasSimilarElement);
.as-console-wrapper { min-height: 100%!important; top: 0; }
然而,对于非常大的结果集,这是低效的-我不是"大0"表示法专家,但我相信这将是O(n2) -您可能会比较result1.length
*result2.length
乘以
对于这个简单的例子,您可以从两个结果中提取.name
,并创建一个Set
…如果Set
的大小小于合并后的结果.length
,则表示存在重复
在这里,您将每个结果迭代一次-如果两个集合都有1000个元素,则迭代2000次,而使用上面的朴素方法则为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:'johnny@example.com'},
{id:4, name:'Bobby', email:'bobby@example.com'}
];
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:'johnny@example.com'},
{id:4, name:'Bobby', email:'bobby@example.com'}
];
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; }
从上面的注释…
" OP需要在
result2
中result1
的item.name
值相等的项目find
,而不是直接比较result2
中不存在的(例如undefined
)name
属性。">
或者正如3limin4t0or正确建议的那样,可以再次将find
交换为另一个some
。
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: 'lea@example.com' },
{ id: 2, name: 'John', email: 'johnny@example.com' },
];
const result3 = [
{ id: 5, name: 'Lea', email: 'lea@example.com' },
];
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: 'lea@example.com' },
{ id: 2, name: 'John', email: 'johnny@example.com' },
];
const result3 = [
// Attention,
// A matching `id` and a non matching `name`.
{ id: 1, name: 'Lea', email: 'lea@example.com' },
];
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; }