Фильтровать массив объектов на основе ввода массива - PullRequest
3 голосов
/ 23 сентября 2019

У меня есть Array из Objects.

Каждый массив объектов содержит массив items, и каждый элемент в этом массиве является объектом, содержащим массив category:

var obj = [
  // first object
  {
    label: 'Label 1',
    // first items
    items: [
      {
        id: 1,
        itemName: 'Item Name 1',
        img: 'imgs/path-to1.jpeg',
        sizes: [],
        colors: [],
        // first category
        category: [
          'I',
          'E',
          'M'
        ],
        defaultChoices: {}
      },
      {
        id: 2,
        itemName: 'Item Name 2',
        img: 'imgs/path-to2.jpeg',
        sizes: [],
        colors: [],
        // second category
        category: [
          'I',
          'E'
        ],
        defaultChoices: {}
      },
      {
        id: 3,
        itemName: 'Item Name 3',
        img: 'imgs/path-to3.jpeg',
        sizes: [],
        colors: [],
        // third category
        category: [
          'I'
        ],
        defaultChoices: {}
      },
    ]
  },
  // second object
  {
    label: 'Label 2',
    // second items
    items: [
      {
        id: 7,
        itemName: 'Item Name 7',
        img: 'imgs/path-to7.jpeg',
        sizes: [],
        colors: [],
        // fourth category
        category: [
          'I',
          'M'
        ],
        defaultChoices: {}
      },
      ...

, просто чтобы прояснить ситуацию, типичный прямой доступ к category будет выполняться следующим образом: obj[0].items[0].category.

С внешнего интерфейса приложения пользователь, основываясь на своем выборе, можете отправить в приложение один из следующих массивов:

  • ['I'];
  • ['E'];
  • ['M'];
  • ['I','E'];
  • ['I','M'];
  • ['E','M'];
  • ['I','E','M'];
  • ...;

Тогда приложение должно вернуть отфильтрованный массив obj : если, например, пользователь отправил ['I'], массив должен содержать любые объекты, в которых категория содержит 'I'.Если пользователь отправил ['E','M'], массив должен содержать любой объект, в котором категория содержит ['E','M'] (независимо от того, является ли категория ['E','M','I']) и т. Д.

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

var hs = [
    {name: 'Batman', franchise: 'DC'},
    {name: 'Ironman', franchise: 'Marvel'}
];

var marvels =  heroes.filter(function(h) {
    return hs.franchise == 'Marvel';
});

Any help is appreciated.

[ОБНОВЛЕНИЕ] Я добавляю более реалистичный образец данных, извините, что не предоставил его раньше: https://drive.google.com/open?id=1sdRx6sQ-cnRXJ8YCe4QH2Sy5fa5mopYW

Ответы [ 4 ]

3 голосов
/ 23 сентября 2019

Если вы хотите отфильтровать по категории, в которой число object в массиве остается неизменным (даже все элементы в этом объекте отфильтрованы, и в объекте нет элемента), то это должно быть то, что выwant:

var obj = [ // I removed some unnecessary params to make it clear, which shouldn't affect any
  {
    label: 'Label 1',
    items: [
      {
        id: 1,
        category: ['I', 'E', 'M'],
      },
      {
        id: 2,
        category: ['I', 'E'],
      },
      {
        id: 3,
        category: ['I'],
      },
    ]
  },
  {
    label: 'Label 2',
    items: [
      {
        id: 7,
        category: ['I', 'M'],
      },
    ]}
]


function filterByCategory(obj, categories) {
  return obj.map( o => ({
    ...o, // copy everything(i.e. label, items)
    items: o.items.filter(item => // modify items in the obj
       categories.some(c => item.category && item.category.includes(c)) // keep item if some categories are in item
    )
  }))
}
const filteredObj = filterByCategory(obj, ['I', 'E'])
console.log(filteredObj)

Если вы хотите дополнительно отфильтровать объект, которого нет, вы можете добавить .filter(o => o.items.length) в конце filterByCategory.

Live Пример:

var data = [ { label: 'Label 1', items: [{ id: 1, itemName: 'Item Name 1', img: 'imgs/path-to1.jpeg', sizes: [], colors: [], category: [ 'I', 'E', 'M' ], defaultChoices: {} }, { id: 2, itemName: 'Item Name 2', img: 'imgs/path-to2.jpeg', sizes: [], colors: [], category: [ 'I', 'E' ], defaultChoices: {} }, { id: 3, itemName: 'Item Name 3', img: 'imgs/path-to3.jpeg', sizes: [], colors: [], category: [ 'I' ], defaultChoices: {} }, ] }, { label: 'Label 2', items: [{ id: 7, itemName: 'Item Name 7', img: 'imgs/path-to7.jpeg', sizes: [], colors: [], category: [ 'I', 'M' ], defaultChoices: {} }] } ]; 

function filterByCategory(data, category) {
  return data.map(obj => {
    return { ...obj,
      "items": obj.items.filter(item =>
        category.some(value => item.category && item.category.includes(value))
      )
    };
  });
}

console.log(filterByCategory(data, ['E', 'M']));
2 голосов
/ 23 сентября 2019

Этот код перебирает все Объекты и элементы и создает новый Объект только с элементами, которые имеют указанные Категории.Более подробное описание Кодекса в комментариях:

// function where you enter the Objects and the Categories you want to filter
function getFilterObjectItems(objs, categories){
  // Filtered Objects
  return objs.map(function(obj) {
    // Creates a new Item
    var newObject = {label: obj.label, items:[]};
    //iterate through all items in an Object looking for items with matching Category
    obj.items.forEach(function(item){
      // if one category entry matches add item to new Object
      //  the "some" function returns "true" or "false" if one item matches the critieria
      if(item && item.category && item.category.some && item.category.some(cat => searchedCAT.indexOf(cat)>-1)){
        // the original item will be added to the new item ist
        newObject.items.push(item);
      }
    });
    return newObject;
  })
  // filters all New Objects that don't have items
  .filter(newObject => newObject.items.length>0);
}


// DATA from the Question
var obj = [
  // first object
  {
    label: 'Label 1',
    // first items
    items: [
      {
        id: 1,
        itemName: 'Item Name 1',
        img: 'imgs/path-to1.jpeg',
        sizes: [],
        colors: [],
        // first category
        category: [
          'I',
          'E',
          'M'
        ],
        defaultChoices: {}
      },
      {
        id: 2,
        itemName: 'Item Name 2',
        img: 'imgs/path-to2.jpeg',
        sizes: [],
        colors: [],
        // second category
        category: [
          'I',
          'E'
        ],
        defaultChoices: {}
      },
      {
        id: 3,
        itemName: 'Item Name 3',
        img: 'imgs/path-to3.jpeg',
        sizes: [],
        colors: [],
        // third category
        category: [
          'I'
        ],
        defaultChoices: {}
      },
    ]
  },]

// search Categories
var searchedCAT = ['I'];


// Calling the Function
console.info(getFilterObjectItems(obj, searchedCAT));
1 голос
/ 23 сентября 2019

Это решение использует четыре метода Array для фильтрации массива obj: .filter, .some, .every и .includes.

// __Simplified version of the 'obj' array__
var obj = [
  {
    label: '1',
    items: [
      {id:1, category:['I','E','M']},
      {id:2, category:['I','E'] },
      {id:3, category:['I']}
    ]
  },
  {
    label: '2',
    items: [
      { id:7, category: ['I','M']}
    ]
  }
];


// __The filter function__
// (Takes an array of user input, and filters the global
//   `obj` array to return a new array)
function filterObj(inputArray){ 
  const filtered = obj.filter( object => // Keep the object if...
    object.items.some( item => // some item in the object passes this test:
      inputArray.every( value => // For every value in the input array...
        item.category.includes(value) // the item's 'category' array includes value
      )
    )
  );
  return filtered;
}

// __Testing function__
// (Calls `filterObj` on a test array and logs the results)
function test(input){
  console.log(`Testing this input: ${ input }`);
  console.log("Obects having `some` item where `every` value in the input array is `included`:");
  filterObj(input).forEach( matchingObject => { console.log(matchingObject.label); });
  console.log("");
}

// __Tests__
test(['I','M']);
test(['I','E']);

(Примечание. Выходные данные соответствуют исходной спецификации OP: «если, например, пользователь отправил ['I'], массив должен содержатьлюбые объекты, в которых категория содержит «I»)

1 голос
/ 23 сентября 2019
const UserChoice = ['E', 'X'];
const filtered = obj.filter(o => {
  const filteredItems = o.items.filter(item =>
    item.category.map(c => UserChoice.includes(c)).includes(true)
  );
  if (filteredItems.length > 0) {
    o.items = filteredItems;
    return o;
  }
});

«отфильтрованный» будет иметь ваш отфильтрованный объект

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