0

I have the following array of books. I want a write a function that receives the target book and the language, removes that book (key, value) from the nested object and returns the new array.

let books = [
  {
    language: 'spanish',
    books: {
      book_1: 'book1_spanish',
      book_2: 'book2_spanish',
      book_3: 'book3_spanish'
    }
  },
  {
    language: 'italian',
    books: {
      book_1: 'book1_italian',
      book_2: 'book2_italian',
      book_3: 'book3_italian'
    }
  }
];

let targetBook = { book_1: 'book1_spanish' };
let language = 'spanish';

I am stuck at looping over the nested object.

function removeTargetBook(lan, target) {
  return books.map(book => {
    if (book.language == lan) {
      Object.values(book).map(value => {});
    }
  });
}

It should return the same array without book_1: 'book1_spanish'. This is my stackblitz: https://stackblitz.com/edit/js-yxcrbq

Thanks.

3
  • Take a look at this: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Aug 30, 2021 at 19:18
  • Know about it, can't do the nesting part. Commented Aug 30, 2021 at 19:26
  • 1
    I got you, check out the answer Commented Aug 30, 2021 at 19:34

3 Answers 3

2

You want to be using the delete operator.

I took the liberty of expanding on your code a little to show you how using the key of the object in a forEach loop is more efficient than doing a key / value pair comparison. Also note that I am leaving the original books object intact, this is important for unit testable code and data integrity, but you can change/implement as you need.

let books = [
  {
    language: 'spanish',
    books: {
      book_1: 'book1_spanish',
      book_2: 'book2_spanish',
      book_3: 'book3_spanish'
    }
  },
  {
    language: 'italian',
    books: {
      book_1: 'book1_italian',
      book_2: 'book2_italian',
      book_3: 'book3_italian'
    }
  }
];

let targetBook = { book_1: 'book1_spanish' };
let language = 'spanish';
let target = Object.keys(targetBook)[0]; // we only need the 'key' of the targetBook
let result;

function removeTargetBook(books, lan, target) {
  books.forEach(elem => { // some instead of forEach works here as well
    elem.language === lan && (delete elem.books[target]);
  });
  
  return books;
}
// multiple tests for correctness
result = removeTargetBook(books, language, 'fool proof test');
console.log(result);
result = removeTargetBook(books, language, target);
console.log(result);
result = removeTargetBook(books, language, 'book_2');
console.log(result);
result = removeTargetBook(books, language, 'book_3');
console.log(result);

Sign up to request clarification or add additional context in comments.

2 Comments

@zana10 sometimes you dont need a function, in the above solution i wouldnt use a function for a single callback unless you are "deleting books" in multiple places
the data structure being used does not allow for a single item search since everything is stored in an array of objects, I would re-arrange the data structure to be a large object with key being language and value being the content of books, this way as @RicardoSaracino mentioned, you will be able to bypass the need of a callback function and also a loop to match by language
1

My far too complicated version:

let books = [{
    language: 'spanish',
    books: {
      book_1: 'book1_spanish',
      book_2: 'book2_spanish',
      book_3: 'book3_spanish'
    }
  },
  {
    language: 'italian',
    books: {
      book_1: 'book1_italian',
      book_2: 'book2_italian',
      book_3: 'book3_italian'
    }
  }
];

let targetBook = {
  book_1: 'book1_spanish'
};
let language = 'spanish';

function removeTargetBook(lan, target) {
  return books.map(book => {
    if (book.language === lan) {

      return {
        language: book.language,
        books: Object.assign(...Object.keys(book.books).map((key) => ({
          [key]: book.books[key]
        })).filter((e) => (Object.keys(e)[0] !== Object.keys(target)[0]) && Object.values(e)[0] !== Object.values(target)[0])),
      }
    } else {
      return book
    }
  })
}
console.log(removeTargetBook(language, targetBook))

Comments

0

I think something like this should work

function removeTargetBook(lan, target) {
  books.some(book => {
    if (book.language == lan) {
      delete book.books[Object.keys(target)[0]];
      return true;
    }
  });
  return books
}

1 Comment

Please add further details to expand on your answer, such as working code or documentation citations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.