I want to sort through two arrays and determine if any of the objects contain the same key/value pair. Where there is a match by id
, I want to update the tempSearch array object to include the shelf
key/value pair from the matched booksOnShelf object. If no match between the arrays, I want to update that tempSearch object with shelf: "none"
.
I am certain that both arrays have data. Currently, all shelf
data returns as "none".
UPDATE (Including array data example.)
tempSearch = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
booksOnShelf = [{id: 1, shelf: "read"}, {id: 4, shelf: "wantToRead"}];
The final result of tempSearch:
console.log(tempSearch);
// [{id: 1, shelf: "read"}, {id: 2, shelf: "none"}, {id: 3, shelf: "none"}, {id: 4, shelf: "wantToRead"}];
END OF UPDATE
const mergeBooks = () => {
let tempSearch = searchInventory;
let booksOnShelf = bookInventory;
tempSearch.forEach((searchBook, index) => {
booksOnShelf.forEach(book => {
if (searchBook.id === book.id) {
searchBook.shelf = book.shelf;
} else {
searchBook.shelf = "none";
}
})
})
setMergedInventory(tempSearch);
}
CodePudding user response:
You're really close, but the issue is that you're assigning to shelf
in every iteration of the inner loop. Instead, find the book, then if you found it, use it, and if not, assign "none"
:
const mergeBooks = () => {
let tempSearch = searchInventory;
let booksOnShelf = bookInventory;
tempSearch.forEach((searchBook) => {
const book = booksOnShelf.find((book) => book.id === searchBook.id);
searchBook.shelf = book && book.shelf ? book.shelf : "none";
});
setMergedInventory(tempSearch);
};
const searchInventory = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const bookInventory = [{id: 1, shelf: "read"}, {id: 2}, {id: 3}, {id: 4, shelf: "wantToRead"}];
const mergeBooks = () => {
let tempSearch = searchInventory;
let booksOnShelf = bookInventory;
tempSearch.forEach((searchBook) => {
const book = booksOnShelf.find((book) => book.id === searchBook.id);
searchBook.shelf = book && book.shelf ? book.shelf : "none";
});
// setMergedInventory(tempSearch);
console.log(tempSearch);
};
mergeBooks();
.as-console-wrapper {
max-height: 100% !important;
}
That said, a couple of notes:
These days, I'd use a
for-of
loop instead of theforEach
method.There doesn't seem to be any reason for the
tempSearch
/booksOnShelf
variables, they just refer to the same things thatserachInventory
andbookInventory
refer to, so you can just remove them.
So with those changes:
const mergeBooks = () => {
for (const searchBook of searchInventory) {
const book = bookInventory.find((book) => book.id === searchBook.id);
searchBook.shelf = book ? book.shelf : "none";
}
setMergedInventory(searchInventory);
};
const searchInventory = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const bookInventory = [{id: 1, shelf: "read"}, {id: 2}, {id: 3}, {id: 4, shelf: "wantToRead"}];
const mergeBooks = () => {
for (const searchBook of searchInventory) {
const book = bookInventory.find((book) => book.id === searchBook.id);
searchBook.shelf = book && book.shelf ? book.shelf : "none";
}
// setMergedInventory(searchInventory);
console.log(searchInventory);
};
mergeBooks();
.as-console-wrapper {
max-height: 100% !important;
}
You could also replace the conditional operator (? :
) with optional chaining and nullish coalescing:
const mergeBooks = () => {
for (const searchBook of searchInventory) {
const book = bookInventory.find((book) => book.id === searchBook.id);
searchBook.shelf = book?.shelf ?? "none";
}
setMergedInventory(searchInventory);
};
const searchInventory = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const bookInventory = [{id: 1, shelf: "read"}, {id: 2}, {id: 3}, {id: 4, shelf: "wantToRead"}];
const mergeBooks = () => {
for (const searchBook of searchInventory) {
const book = bookInventory.find((book) => book.id === searchBook.id);
searchBook.shelf = book?.shelf ?? "none";
}
// setMergedInventory(searchInventory);
console.log(searchInventory);
};
mergeBooks();
.as-console-wrapper {
max-height: 100% !important;
}
If you're a fan of really condensed code (I'm not), that means you don't need the book
constant anymore:
const mergeBooks = () => {
for (const searchBook of searchInventory) {
searchBook.shelf = bookInventory.find((book) => book.id === searchBook.id)?.shelf ?? "none";
}
setMergedInventory(searchInventory);
};
const searchInventory = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const bookInventory = [{id: 1, shelf: "read"}, {id: 2}, {id: 3}, {id: 4, shelf: "wantToRead"}];
const mergeBooks = () => {
for (const searchBook of searchInventory) {
searchBook.shelf = bookInventory.find((book) => book.id === searchBook.id)?.shelf ?? "none";
}
// setMergedInventory(searchInventory);
console.log(searchInventory);
};
mergeBooks();
.as-console-wrapper {
max-height: 100% !important;
}
If bookInventory
is a very large array, it's not ideal to search through it using a linear search for each book in searchInventory
. Instead, you can create a Map
of ids to books. Looking in a Map
is a sublinear operation (meaning it takes less time, on average, than searching through one by one). Of course, you have the added overhead of building the Map
, so it's a balance.
With that:
const mergeBooks = () => {
// Build the Map
const booksById = new Map(bookInventory.map((book) => [book.id, book]));
// Use it in the process
for (const searchBook of searchInventory) {
const book = booksById.get(searchBook.id);
searchBook.shelf = book?.shelf ?? "none";
}
setMergedInventory(searchInventory);
};
const searchInventory = [{id: 1}, {id: 2}, {id: 3}, {id: 4}];
const bookInventory = [{id: 1, shelf: "read"}, {id: 2}, {id: 3}, {id: 4, shelf: "wantToRead"}];
const mergeBooks = () => {
// Build the Map
const booksById = new Map(bookInventory.map((book) => [book.id, book]));
// Use it in the process
for (const searchBook of searchInventory) {
const book = booksById.get(searchBook.id);
searchBook.shelf = book?.shelf ?? "none";
}
// setMergedInventory(searchInventory);
console.log(searchInventory);
};
mergeBooks();
.as-console-wrapper {
max-height: 100% !important;
}
It might even be useful to maintain bookInventory
as a Map
rather than holding it as an array, if you regularly need to look up books in it by ID.