<!--your preparation HTML code goes here-->
function generateTestData(size) {
const items = Array.from({
length: size
}, (_, i) => ({
id: i,
name: `Item ${i}`
}));
// Randomly select ~75% of items
const selectedItems = items
.filter(() => Math.random() > 0.25)
.map(item => item.id);
return {
bill: {
items
},
selectedItems
};
}
const dataSizes = [100, 1000, 10000, 100000, 1000000];
var data = generateTestData(Math.floor(Math.random() * 5));
var bill = data.bill;
var selectedItems = data.selectedItems;
const allSelected = bill.items.every(({ id }) => selectedItems.includes(id));
return allSelected;
const allSelected = ((selected) =>
bill.items.every(({ id }) => selected.has(id))
)(new Set(selectedItems));
return allSelected;
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
Array.every Array.includes | |
Array.every Set.has with Set creation |
Test name | Executions per second |
---|---|
Array.every Array.includes | 102695384.0 Ops/sec |
Array.every Set.has with Set creation | 32997224.0 Ops/sec |
In the provided benchmark, we're comparing two different approaches for checking if a set of selected item IDs is present in a larger list of item IDs (the "bill"). The main focus of the tests is the efficiency of using Array.every
combined with Array.includes
versus Array.every
combined with the Set
data structure.
Array.every + Array.includes:
const allSelected = bill.items.every(({ id }) => selectedItems.includes(id));
return allSelected;
bill.items
array and checks if its id
is included in the selectedItems
array using Array.includes
.Array.every + Set.has:
const allSelected = ((selected) => bill.items.every(({ id }) => selected.has(id)))(new Set(selectedItems));
return allSelected;
selectedItems
array into a Set
, which allows for faster lookups. It then checks if every item's id
exists in this set using Set.has
method.Array.every + Array.includes:
includes
conveys the intent directly.includes
method has linear time complexity (O(n)), meaning that for each item in bill.items
, it needs to potentially traverse the entire selectedItems
array.Array.every + Set.has:
Set
allows for average constant time complexity (O(1)) for lookups, which dramatically speeds up the process when checking for existence.n
is the size of bill.items
and m
is the size of selectedItems
) to O(n) after the creation of the set.Set
, which might be a consideration if memory is limited or if selectedItems
is very large.From the benchmark results, we can interpret the following:
Performance:
Array.every + Array.includes
approach had an execution rate of approximately 102.7 million operations per second.Array.every + Set.has
approach had a lower execution rate of approximately 32.9 million operations per second.However, this comparison might seem counter-intuitive initially, because the performance characteristics can differ based on specific data and execution environments. Generally, the Set
approach should outperform the includes
approach, especially as the size of bill.items
and selectedItems
increases. It's possible that the benchmark was run on a size where the overhead of creating a Set
negated its lookup speed benefits.
In conclusion, while the Set.has
method generally provides better performance due to its average-case O(1) lookups, the inclusion of the set creation time can have a significant impact on overall performance, depending on the data size.
Other Alternatives:
selectedItems
into an object where keys are the item IDs for faster lookups (similar in performance to a Set
).Map
: If additional data is needed alongside the IDs, using a Map
could be a consideration.When deciding which approach to use, consider factors such as the expected size of your data, the frequency of checks, and the importance of code clarity and maintainability.