Перебирая вложенные массивы и получая эксклюзивные результаты - PullRequest
0 голосов
/ 28 апреля 2018

У меня есть некоторые проблемы (базовая вложенность и фильтрация JS) при извлечении «эксклюзивных» отфильтрованных данных из объекта вложенного массива. Код для проекта React. Я могу ввести lodash, если требуется.

У меня есть массив с 1 или более (и, возможно, также 0, в случае чего возвращаются значения по умолчанию) строк в массиве:

let arrayA = ["string-1", "string-2"]; //assume them to be skill slugs 

Я объявляю новый массив для хранения данных, которые помещаются в него позже:

let newArr1 = [];

Мой вложенный основной массив:

      /*Top level skillset category, within each of which a skills array resides (propC).
        Within each skill there is an array of projects associated with that particular skill (propC3). 
        Projects can have multiple skills so projects in one skill may perhaps reside in other skills as well.*/
     let arrayB =[ //the top level skillset category
        {
        "propA": "valueA1",
        "propB": "valueB1",
        "propC":[ //the skills array
            {
            "propC1": "valueC11",
            "matchthis": "string-1", //the unique skill slug
            "proppC2": "valueC12",

            "propC3": [ //projects
                {
                propC31: "valueC131",
                },
                {
                propC32: "valueC132",
                }

                ]

            },

            {
                "propC1": "valueC12",
                "matchthis": "string-2",
                "proppC2": "valueC12",

                "propC3": [
                    {
                    propC31: "valueC131",
                    },
                    {
                    propC32: "valueC232",
                    }

                    ]

                }

        ],
        "propD": "valueD1"      
        },
        {
        "propA": "valueA2",
        "propB": "valueB2",
        "propC":[
            {
            "propC1": "valueC21",
            "matchthis": "string-2",
            "proppC2": "valueC22",
            "proppC3": [
                {
                propC31: "valueC231",
                },
                {
                propC32: "valueC132",
                }

                ]

            }
        ],
        "propD": "valueD1"      
        },


    ]

Мне нужно отфильтровать вложенный массив arrayB, чтобы возвращалось только подмножество данных, основанное на строках в массиве arrayA. Я использую массив newArray1 для хранения этих данных. У меня могут быть дубликаты данных (когда я помещаю их в массив newArray), поэтому я могу также удалить их либо с помощью vanilla JS, либо lodash.

Моя попытка:

arrayA.map((a,i)=>{
   return arrayB.filter((b,j)=>{
     return b.propC.filter((c,k)=>{
        return a===c.matchthis
       }).map((o,i)=>{
        o.propC3.map((o,i)=>{
         newArr1.push(o)
        })

      })                 
     })
   })

Когда я нажимаю данные, есть вероятность дубликатов, поэтому я удаляю их следующим образом:

 // newArr1 =  newArr1.filter((s1, pos, arr) => arr.findIndex((s2)=>s2.project_id === s1.project_id) === pos); //JS
 newArr1 = _.uniqBy(newArr1, 'project_id'); //lodash

Кажется, я не могу запустить exclusion. Под исключительным я подразумеваю, что данные, которые находятся в newArray1 (проекты), должны иметь только те проекты, в которых все навыки переданы в arrayA - если один из них не удался, результата нет. Если я прошел ["html5", "css", "react"], то должны быть возвращены только те проекты, которые содержат эти навыки.

Я могу получить «инклюзивные» результаты, используя мой текущий подход.

Сценарий таков: пользователь выбирает один или несколько навыков (из набора навыков), и я отображаю проекты, которые включают все эти навыки (эксклюзивный подход). Так как навыки находятся в категориях, навыки могут иногда находиться в более чем одной категории. У меня может быть переключатель, который позволяет пользователю выбирать между включающей и исключительной фильтрацией, но определенно не сейчас.

Вот более-менее актуальный объект массива, сокращенный для краткости:

       [{
        skillltype_id:”0”,
        skills: [
       {
        skill_id: ”0”,
        skill_name: "HTML5”,    
        skill_slug:"html5”,
        ….
        projects: [
             {
                     project_id :”0”,
                     project_name: “Lorem Ipsum 1”,         
                     project_slug: “a-slug”
                     …
             },

             {
                     project_id :”2”,
                     project_name: “Lorem Ipsum 2”,         
                     project_slug: “b-slug”
                     …
             },
             ….
         ]

     },
     {
     skill_id: ”2”,
     skill_name: “javascript”,
     skill_slug:”javascript”,
    ….
     projects: [
             {
                     project_id :”100”,
                     project_name: “Lorem Ipsum 1”,                      
                     project_slug: “a-slug”
                     …

             },
             {
                     project_id :”2”,
                     project_name: “Lorem Ipsum 2”,                      
                     project_slug: “b-slug”
                     …
             },
             ….
         ]
     }

     ],
     skilltype_description:"Lorem Ipsum”,
     skilltype_name:”Lorem Ipsum”,
     skilltype_shortdescription:"Lorem Ipsum”,
     },

     ……..
     ……

     ]

ОБНОВЛЕНИЕ: Добавление желаемого результата:

На основе примеров массивов, показанных в верхней части этого вопроса, передавая ["html5","css"] как arrayA

должен возвращать массив со списком проектов, который содержится внутри arrayB> propC> propC3 как newArray1 (или любое имя), где каждый элемент в arrayA соответствует matchthis собственность в propC.

Если соответствует только одна строка (например, html5), то она не может рассматриваться и возвращает пустой массив. Все пропущенные строки должны совпадать, чтобы считаться эксклюзивными.

Для большей ясности: на примере массива B с почти фактическими данными (ближе к концу вопроса), передавая ["html5","css"] в виде массива

должен возвращать массив проектов, содержащийся в skills> projects, где каждый элемент (строка) соответствует свойству skill_slug в массиве skills.

  • arrayA - массив значений, которые я собираюсь использовать для поиска
  • arrayB - это массив категорий навыков, который состоит из массива навыков с именем propC.
  • Каждый навык внутри propC состоит из массива проектов с именем propC3, а также имеет свойство matchthis, которое можно использовать для сопоставления строки с arrayA.

Обновление 2: добавление дополнительной информации для ясности

В проекте используются redux и thunks, так что принцип определенно не является мутативным. Я не упомянул об этом, так как думал, что эта конкретная проблема была скорее проблемой базового вида JS.

Этот конкретный раздел кода находится в action creator до отправки.

Я должен упомянуть, что я делаю slice() из функционального параметра getState() (объекта, возвращаемого хранилищем избыточного числа) несколькими строками ранее, чтобы получить arrayB, так что, по сути, код, который я добавил здесь мутирует, потому что я работаю над уникальной копией. Окончательный массив (newArray1) будет передан в качестве полезной нагрузки для состояния.

Так что на самом деле не имеет значения, создается ли новый массив (на самом деле newArray1 - это вновь созданный массив только для хранения данных из операций фильтрации) или мутирует существующий массив (код добавлен здесь) ,

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

Это мой первый react-redux проект (помимо учебных проектов), поэтому я стараюсь быть осторожным с изменением состояния и иногда зацикливаюсь на создании копий.

поток:

  • пользователь выбирает навык, я отправляю действие и добавляю слаг навыка в массив selectedskill, который существует в магазине
  • выше - Promise, поэтому в then я отправляю действие для отображения соответствующих проектов на основе выбранных навыков
  • В этом действии возникает эта проблема. Я использую getState() и slice(), чтобы получить копию объекта skillsets из магазина (arrayB), в котором есть все наборы навыков, каждый из которых имеет навыки и каждый навык также состоит из соответствующих проектов. У меня также есть массив selectedskills (arrayA). Теперь мне нужно сопоставить их и отфильтровать вложенные эксклюзивные проекты (arrayB> propC> propC3)
  • предполагая, что я получаю нужные мне данные (с новым массивом или путем всего лишь нескольких цепочек отображения и фильтрации), я возвращаю этот массив в качестве полезной нагрузки, которая будет отправлена ​​редуктору, чтобы мой пользовательский интерфейс теперь отображал проекты, относящиеся к все выбранные навыки.
  • (примечание: у меня есть массив всех доступных проектов. Очень рано, когда страница открывается, я извлекаю все эти проекты из всех skillsets и skills и после дедупликации сохраняю их как большой и уникальный массив allprojects, который я могу использовать при необходимости. Я не использую его, как мне кажется, учитывая, что данные конечны, поэтому мой массив skillsets не будет слишком большим, и я могу продолжать использовать его в качестве основного источника данные и использовать их при необходимости)

1 Ответ

0 голосов
/ 28 апреля 2018

Так вот один из способов сделать это. Сначала мы создаем объект Projects:

let Projects = {};

Теперь мы заполним это всеми требованиями к навыкам проектов в массиве B:

arrayB.map((b) => { 
  b.propC.map((c) => { 
    // note had to use old-style function here to get this to be correctly assigned in Firefox
    c.propC3.map(function (c3) {
      // get the name of the project
      let name = c3[Object.keys(c3)[0]];
      if (Projects.hasOwnProperty(name))
        Projects[name].push(this.toString());
      else
        Projects[name] = [this.toString()];
    }, c.matchthis); 
  }); 
});

В этом примере console.log(Projects) дает:

{…}
valueC131: Array [ "string-1", "string-2" ]
valueC132: Array [ "string-1", "string-2" ]
valueC231: Array [ "string-2" ]
valueC232: Array [ "string-2" ]
__proto__: Object { … }

Теперь мы можем просто сравнить элементы Projects с навыками в arrayA. Любые проекты, которые требуют всех навыков в arrayA, будут помещены в newArr:

let newArr = [];
for (p in Projects) {
  if (Projects.hasOwnProperty(p)) {
    if (arrayA.reduce((t, s) => { return t && (Projects[p].indexOf(s) >= 0); }, true)) newArr.push(p);
  }
}
console.log(newArr);

Выход:

Array [ "valueC131", "valueC132" ]

Мы также можем проверить проекты, которые требуют любых навыков в arrayA с небольшим изменением кода:

newArr = [];
for (p in Projects) {
  if (Projects.hasOwnProperty(p)) {
    if (arrayA.reduce((t, s) => { return t || (Projects[p].indexOf(s) >= 0); }, false)) newArr.push(p);
  }
}
console.log(newArr);

Выход:

Array [ "valueC131", "valueC132", "valueC232", "valueC231" ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...