intersectionBy
Returns the intersection of two arrays using a transformation function to determine equality. Creates a new array containing elements from the source array that have matching transformed values in the target array. The mapper function is used to extract comparable values from elements in both arrays for intersection comparison.
Signature
const intersectionBy: <Type1, Type2>(source: Type1[], target: Type2[], mapper: (item: Type1 | Type2) => unknown) => Type1[]
Parameters
| Name | Type | Description |
|---|---|---|
source | - | First array to find intersection from |
target | - | Second array to compare against |
mapper | - | Function to transform elements into comparable values |
Returns
Array of elements from source that form the intersection with target
Examples
Compare objects by ID
import { intersectionBy } from '@winglet/common-utils';
const users = [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
{ id: 3, name: 'Charlie', role: 'user' }
];
const activeUsers = [
{ id: 1, status: 'active' },
{ id: 3, status: 'active' }
];
const activeUserDetails = intersectionBy(users, activeUsers, user => user.id);
console.log(activeUserDetails);
// [{ id: 1, name: 'Alice', role: 'admin' }, { id: 3, name: 'Charlie', role: 'user' }]
Compare strings by length
const words = ['cat', 'dog', 'elephant', 'ant', 'butterfly'];
const lengths = ['car', 'bus']; // length 3
const wordsWithMatchingLength = intersectionBy(words, lengths, word => word.length);
console.log(wordsWithMatchingLength); // ['cat', 'dog', 'ant']
Complex object intersection
interface Product {
id: number;
name: string;
category: string;
price: number;
}
interface Category {
name: string;
isActive: boolean;
}
const products: Product[] = [
{ id: 1, name: 'Laptop', category: 'Electronics', price: 999 },
{ id: 2, name: 'Book', category: 'Education', price: 29 },
{ id: 3, name: 'Phone', category: 'Electronics', price: 699 }
];
const activeCategories: Category[] = [
{ name: 'Electronics', isActive: true },
{ name: 'Sports', isActive: true }
];
// Find products in active categories
const activeProducts = intersectionBy(
products,
activeCategories,
item => 'category' in item ? item.category : item.name
);
console.log(activeProducts); // [{ id: 1, name: 'Laptop', ... }, { id: 3, name: 'Phone', ... }]
Date-based intersection
const events = [
{ name: 'Meeting', date: new Date('2024-01-15') },
{ name: 'Conference', date: new Date('2024-02-20') },
{ name: 'Workshop', date: new Date('2024-03-10') }
];
const holidays = [
{ name: 'Presidents Day', date: new Date('2024-02-20') },
{ name: 'Memorial Day', date: new Date('2024-05-27') }
];
// Find events that fall on holidays
const conflictingEvents = intersectionBy(
events,
holidays,
item => item.date.getTime()
);
console.log(conflictingEvents); // [{ name: 'Conference', date: ... }]
Nested property comparison
const employees = [
{ id: 1, profile: { department: 'Engineering', level: 'Senior' } },
{ id: 2, profile: { department: 'Marketing', level: 'Junior' } },
{ id: 3, profile: { department: 'Engineering', level: 'Junior' } }
];
const departments = [
{ name: 'Engineering', budget: 100000 },
{ name: 'Sales', budget: 80000 }
];
const engineeringEmployees = intersectionBy(
employees,
departments,
item => 'profile' in item ? item.profile.department : item.name
);
console.log(engineeringEmployees);
// [{ id: 1, profile: { department: 'Engineering', ... } }, { id: 3, profile: { department: 'Engineering', ... } }]
Email domain intersection
const users = [
{ name: 'Alice', email: 'alice@company.com' },
{ name: 'Bob', email: 'bob@gmail.com' },
{ name: 'Charlie', email: 'charlie@company.com' }
];
const allowedDomains = ['company.com', 'partner.org'];
const companyUsers = intersectionBy(
users,
allowedDomains,
item => typeof item === 'string' ? item : item.email.split('@')[1]
);
console.log(companyUsers);
// [{ name: 'Alice', email: 'alice@company.com' }, { name: 'Charlie', email: 'charlie@company.com' }]
Working with different types
interface Person { name: string; age: number; }
interface AgeGroup { min: number; max: number; }
const people: Person[] = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 35 },
{ name: 'Charlie', age: 45 }
];
const targetAges = [25, 35, 55];
const matchingAgePeople = intersectionBy(
people,
targetAges,
item => typeof item === 'number' ? item : item.age
);
console.log(matchingAgePeople); // [{ name: 'Alice', age: 25 }, { name: 'Bob', age: 35 }]
Playground
import { intersectionBy } from '@winglet/common-utils'; const users = [ { id: 1, name: 'Alice', role: 'admin' }, { id: 2, name: 'Bob', role: 'user' }, { id: 3, name: 'Charlie', role: 'user' } ]; const activeUsers = [ { id: 1, status: 'active' }, { id: 3, status: 'active' } ]; const activeUserDetails = intersectionBy(users, activeUsers, user => user.id); console.log(activeUserDetails); // [{ id: 1, name: 'Alice', role: 'admin' }, { id: 3, name: 'Charlie', role: 'user' }]
Notes
Performance: Uses Set for O(1) average case lookup after mapping target array. Time complexity is O(n + m) where n is source length and m is target length.
Mapper Function: The mapper function is called once for each element in both arrays. Ensure the mapper function is pure and returns consistent values for the same input.
Type Safety: Supports different types for source and target arrays as long as the mapper function can handle both types and returns comparable values.
Order Preservation: Maintains the original order of elements from the source array in the result array.
Duplicate Handling: If the source array contains elements that map to the same value and that value exists in the mapped target array, all matching elements from source will be included in the result.