Подсчет вхождения значений в массиве объектов в другой массив объектов - PullRequest
1 голос
/ 22 мая 2019

Мне нужно создать запрос Graphql, который выводит данные из двух массивов объектов. Массивы:

  const authors = [
    {
      name: 'Robert Martin',
      id: 'afa51ab0-344d-11e9-a414-719c6709cf3e',
      born: 1952
    },
    {
      name: 'Martin Fowler',
      id: 'afa5b6f0-344d-11e9-a414-719c6709cf3e',
      born: 1963
    },
    {
      name: 'Fyodor Dostoevsky',
      id: 'afa5b6f1-344d-11e9-a414-719c6709cf3e',
      born: 1821
    },
    {
      name: 'Joshua Kerievsky', // birthyear not known
      id: 'afa5b6f2-344d-11e9-a414-719c6709cf3e'
    },
    {
      name: 'Sandi Metz', // birthyear not known
      id: 'afa5b6f3-344d-11e9-a414-719c6709cf3e'
    }
  ];

И

  const books = [
    {
      title: 'Clean Code',
      published: 2008,
      author: 'Robert Martin',
      id: 'afa5b6f4-344d-11e9-a414-719c6709cf3e',
      genres: ['refactoring']
    },
    {
      title: 'Agile software development',
      published: 2002,
      author: 'Robert Martin',
      id: 'afa5b6f5-344d-11e9-a414-719c6709cf3e',
      genres: ['agile', 'patterns', 'design']
    },
    {
      title: 'Refactoring, edition 2',
      published: 2018,
      author: 'Martin Fowler',
      id: 'afa5de00-344d-11e9-a414-719c6709cf3e',
      genres: ['refactoring']
    },
    {
      title: 'Refactoring, edition 3',
      published: 2018,
      author: 'Martin Fowler',
      id: 'afa5de00-344d-11e9-a414-719c6709cf3e',
      genres: ['refactoring']
    },
    {
      title: 'Refactoring, edition 4',
      published: 2018,
      author: 'Martin Cowler',
      id: 'afa5de00-344d-11e9-a414-719c6709cf3e',
      genres: ['refactoring']
    },
    {
      title: 'Refactoring to patterns',
      published: 2008,
      author: 'Joshua Kerievsky',
      id: 'afa5de01-344d-11e9-a414-719c6709cf3e',
      genres: ['refactoring', 'patterns']
    },
    {
      title: 'Practical Object-Oriented Design, An Agile Primer Using 
       Ruby',
      published: 2012,
      author: 'Sandi Metz',
      id: 'afa5de02-344d-11e9-a414-719c6709cf3e',
      genres: ['refactoring', 'design']
    },
    {
      title: 'Crime and punishment',
      published: 1866,
      author: 'Fyodor Dostoevsky',
      id: 'afa5de03-344d-11e9-a414-719c6709cf3e',
      genres: ['classic', 'crime']
    },
    {
      title: 'The Demon ',
      published: 1872,
      author: 'Fyodor Dostoevsky',
      id: 'afa5de04-344d-11e9-a414-719c6709cf3e',
      genres: ['classic', 'revolution']
    }
  ];

Требуемый формат вывода для запроса, подобного следующему:

query {
  allAuthors {
  name
  bookCount
 }

}

выглядит так:

    "data": {
      "allAuthors": [
        {
          "name": "Robert Martin",
          "bookCount": 2
        },
        {
          "name": "Martin Fowler",
          "bookCount": 1
        },
        {
          "name": "Fyodor Dostoevsky",
          "bookCount": 2
        },
        {
          "name": "Joshua Kerievsky",
          "bookCount": 1
        },
        {
          "name": "Sandi Metz",
          "bookCount": 1
        }
      ]
    }

Я нашел способ подсчитать количество книг для каждого автора и вывести данные в нужном формате (хороший пример этого здесь: Суммировать количество вхождений в массиве объектов с помощью Array # Reduce ). Однако этот подход игнорирует другие поля в данных, такие как «рожденный» и «жанры». Если бы я расширил запрос так:

    query {
     allAuthors {
      name
      bookCount
      born
     }
   }

Это ничего не выведет для поля "рожденный". Каков был бы разумный способ создать распознаватель запросов? Оператор спреда? Уменьшить

* РЕДАКТИРОВАТЬ * Мое излишне сложное решение для подсчета книг здесь:

 const newBooks = books.reduce((acc, cv) => {
    const arr = acc.filter(obj => {
      return obj.author === cv.author;
    });

    if (arr.length === 0) {
      acc.push({ name: cv.author, born: cv.born, bookCount: 1 });
    } else {
      arr[0].bookCount += 1;
    }

    return acc;
  }, []);
  const array = [];
  books.forEach(book => {
    const object = {
      name: book.author
    };
    array.push(object);
    return array;
  });
  const unique = array.map(a => a.name);
  result = {};
  for (var i = 0; i < unique.length; ++i) {
    if (!result[unique[i]]) result[unique[i]] = 0;
    ++result[unique[i]];
  }
  const entries = Object.entries(result);
  const finalAnswer = [];
  entries.forEach(entry => {
    const object = {
      name: entry[0],
      bookCount: entry[1]
    };
    finalAnswer.push(object);
    return finalAnswer;
  });
  console.log(finalAnswer);

Ответы [ 2 ]

3 голосов
/ 22 мая 2019

Вы можете map авторов и использовать filter, чтобы получить bookCount для каждого author

const authors=[{name:'Robert Martin',id:'afa51ab0-344d-11e9-a414-719c6709cf3e',born:1952},{name:'Martin Fowler',id:'afa5b6f0-344d-11e9-a414-719c6709cf3e',born:1963},{name:'Fyodor Dostoevsky',id:'afa5b6f1-344d-11e9-a414-719c6709cf3e',born:1821},{name:'Joshua Kerievsky',id:'afa5b6f2-344d-11e9-a414-719c6709cf3e'},{name:'Sandi Metz',id:'afa5b6f3-344d-11e9-a414-719c6709cf3e'}],
      books=[{title:'Clean Code',published:2008,author:'Robert Martin',id:'afa5b6f4-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Agile software development',published:2002,author:'Robert Martin',id:'afa5b6f5-344d-11e9-a414-719c6709cf3e',genres:['agile','patterns','design']},{title:'Refactoring, edition 2',published:2018,author:'Martin Fowler',id:'afa5de00-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Refactoring, edition 3',published:2018,author:'Martin Fowler',id:'afa5de00-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Refactoring, edition 4',published:2018,author:'Martin Cowler',id:'afa5de00-344d-11e9-a414-719c6709cf3e',genres:['refactoring']},{title:'Refactoring to patterns',published:2008,author:'Joshua Kerievsky',id:'afa5de01-344d-11e9-a414-719c6709cf3e',genres:['refactoring','patterns']},{title:'Practical Object-Oriented Design, An Agile Primer Using Ruby ',published:2012,author:'Sandi Metz',id:'afa5de02-344d-11e9-a414-719c6709cf3e',genres:['refactoring','design']},{title:'Crime and punishment',published:1866,author:'Fyodor Dostoevsky',id:'afa5de03-344d-11e9-a414-719c6709cf3e',genres:['classic','crime']},{title:'The Demon ',published:1872,author:'Fyodor Dostoevsky',id:'afa5de04-344d-11e9-a414-719c6709cf3e',genres:['classic','revolution']}];

const output = authors.map(({ born, name }) => {
  const bookCount = books.filter(b => b.author === name).length;
  return { name, born, bookCount }
})

console.log(output)
2 голосов
/ 22 мая 2019

Я думаю, что вы можете добавить инструкцию к вашей функции редуктора, чтобы добавить нужные поля.Я добавил одну строку и аннотировал оставшуюся часть метода, чтобы вы могли видеть, что происходит:

const newBooks = books.reduce((acc, cv) => {
    // acc is an "accumulation" of the results so far.
    // cv is the next item that hasn't been processed.

    // Search for author in "accumulator" array acc. Put results in arr.
    const arr = acc.filter(obj => {
      return obj.author === cv.author;
    });

    if (arr.length === 0) {
      // Haven't seen this author, yet. Add new item to "accumulator" array.
      acc.push({ name: cv.author, born: cv.born, bookCount: 1 });
    } else {
      // This author already exists in "accumulator" array, referenced by arr[0].
      // Update pre-existing item.
      arr[0].bookCount += 1;
      arr[0].born = cv.born;  // <-- This is the new code that is required.
    }

    return acc;
}, []);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...