фильтрация массива внутри массива объектов - PullRequest
0 голосов
/ 09 октября 2019

У меня есть массив, который выглядит примерно так

var categorizedBooks = [
{
 name: "category1",
 books:[
        {name:"book1", bookContainerId: 1, active: true},
        {name:"book2", bookContainerId: 2, active: false},
        {name:"book3", bookContainerId: 2, active: true},
       ]
 },
{
 name: "category2",
 books:[
        {name:"book4", bookContainerId: 1, active: false},
        {name:"book5", bookContainerId: 3, active: true},
        {name:"book6", bookContainerId: 4, active: true},
       ]
 },
{
 name: "category3",
 books:[
        {name:"book7", bookContainerId: 1, active: false},
        {name:"book8", bookContainerId: 2, active: true},
        {name:"book9", bookContainerId: 4, active: false},
       ]
 },
{
 name: "category4",
 books:[
        {name:"book10", bookContainerId: 2, active: false},
        {name:"book11", bookContainerId: 2, active: false},
        {name:"book12", bookContainerId: 4, active: false},
       ]
 }

И я хочу отфильтровать их по двум массивам, которые выглядят примерно так:

bookContainers: [1,3]
isActive: ['active', 'inactive] // an array of strings

Они поступают из входов такэто может измениться когда угодно. Поэтому я хочу сопоставить bookContainers с их bookContainerId, а строковый массив 'active' / 'неактивен' с их логическим активным свойством, и если объект в массиве booksBooks категории пуст, я хочу удалить его.

Так что вв этом случае я получу что-то вроде этого (Требуемый вывод из вышеприведенного):

{
 name: "category1",
 books:[
        {name:"book1", bookContainerId: 1, active: true}
       ]
 },
{
 name: "category2",
 books:[
        {name:"book4", bookContainerId: 1, active: false},
        {name:"book5", bookContainerId: 3, active: true}
       ]
 },
{
 name: "category3",
 books:[
        {name:"book7", bookContainerId: 1, active: false}
       ]
 }

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

public get bookCategories(): Array<CategorizedBook> {
    let cloneToMapOf = [...this.categoriesAndBooks];

    const filteredCategories = cloneToMapOf.map(categorizedbooks => {
        categorizedbooks.books = categorizedbooks.properties.filter(book =>{
            return (rc.includes(books.bookContainerId) && 
sa.includes(book.active ? 'active' : 'inactive'));
        });
        return categorizedbooks;
    });

    const result = filteredCategories.filter(x => x.books.length > 0 && x.books != null);
    return result;
}

Но по какой-то причине этот код модифицирует this.categoriesAndBooks, так что через некоторое время я становлюсь пустым ..

с результатом, который я хочу представить в некотором HTML

    <nz-collapse [nzBordered]="false" *ngFor="let categorizedBook of bookCategories;">
        <nz-collapse-panel [nzHeader]="categorizedBook.name" [nzActive]="true">
            <ng-container *ngFor="let book of categorizedBook.properties; trackBy:trackBy.book">
                <ng-template [ngTemplateOutlet]="bookEditors" [ngTemplateOutletContext]="{book: book, form: bookValueForm}"></ng-template>
            </ng-container>
        </nz-collapse-panel>
    </nz-collapse>

Я сижу с этим часами .. пожалуйста, помогите мне

Ответы [ 2 ]

0 голосов
/ 09 октября 2019

Вы можете взять нужные ключи в массиве и добавить значения вместо некоторых семантических значений, которые необходимо преобразовать в типы данных объекта для тестирования.

В результате получается массив с отфильтрованным подчиненныммассив и пересобран, если вложенный массив содержит некоторые элементы.

var categorizedBooks = [{ name: "category1", books: [{ name: "book1", bookContainerId: 1, active: true }, { name: "book2", bookContainerId: 2, active: false }, { name: "book3", bookContainerId: 2, active: true }] }, { name: "category2", books: [{ name: "book4", bookContainerId: 1, active: false }, { name: "book5", bookContainerId: 3, active: true }, { name: "book6", bookContainerId: 4, active: true }] }, { name: "category3", books: [{ name: "book7", bookContainerId: 1, active: false }, { name: "book8", bookContainerId: 2, active: true }, { name: "book9", bookContainerId: 4, active: false }] }, { name: "category4", books: [{ name: "book10", bookContainerId: 2, active: false }, { name: "book11", bookContainerId: 2, active: false }, { name: "book12", bookContainerId: 4, active: false }] }],
    filters = [['bookContainerId', [1, 3]], ['active', [true, false]]],
    result = categorizedBooks.reduce((r, { name, books }) => {
        books = books.filter(o => filters.every(([k, v]) => v.includes(o[k])));
        if (books.length) r.push({ name, books });
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
0 голосов
/ 09 октября 2019

Обновление

const filteredCategories = cloneToMapOf.map(categorizedbooks => {
        const books = categorizedbooks.properties.filter(book =>{
            return (rc.includes(books.bookContainerId) && 
sa.includes(book.active ? 'active' : 'inactive'));
        });
        return {...categorizedbooks,books}; // so that original array is not mutated.
    });

Я создал внутренний фильтр для книг, которые являются частью контейнера, И активное состояние - это одно из состояний в активном массиве, а затем внешний фильтр для категорий с пустым массивом книг

var categorizedBooks = [
{
 name: "category1",
 books:[
        {name:"book1", bookContainerId: 1, active: true},
        {name:"book2", bookContainerId: 2, active: false},
        {name:"book3", bookContainerId: 2, active: true},
       ]
 },
{
 name: "category2",
 books:[
        {name:"book4", bookContainerId: 1, active: false},
        {name:"book5", bookContainerId: 3, active: true},
        {name:"book6", bookContainerId: 4, active: true},
       ]
 },
{
 name: "category3",
 books:[
        {name:"book7", bookContainerId: 1, active: false},
        {name:"book8", bookContainerId: 2, active: true},
        {name:"book9", bookContainerId: 4, active: false},
       ]
 },
{
 name: "category4",
 books:[
        {name:"book10", bookContainerId: 2, active: false},
        {name:"book11", bookContainerId: 2, active: false},
        {name:"book12", bookContainerId: 4, active: false},
       ]
 }
 ];
var bookContainers = [1,3]
var isActive = ['active', 'inactive'];

var isActiveBoolState = isActive.map(state => state === 'active'); // helper to show which type of active state should be showed.

var result = categorizedBooks.map(category => ({...category, books: category.books.filter(book => bookContainers.includes( book.bookContainerId) && isActiveBoolState.includes(book.active)  )})).filter(category => category.books.length);

console.log(result);
...