Как мне `.filter ()` массив / объект и вернуть новый массив с исходными ключами, а не как индексированный массив / объект в качестве возврата фильтра? - PullRequest
4 голосов
/ 10 апреля 2019
var obj = {

    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    }, 
    112: {
        user_id: 112,
        user_name: "use112",
        isActive: 1
    }, 
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    }, 
    ... 
}

Я хочу отфильтровать все ("isActive" === 0), но оставить ключ установленным (равным идентификатору пользователя) при возврате newObj:

newObj = {

    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    }, 
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    }, 
    ... 
}

Вот что у меня сейчас:

let newObj = Object.values(obj).filter( user => ( (obj.isActive === 0)));

, который возвращает индексированные ключи

  • нет для циклов (если ES6 .forEach() не является обязательным).
  • Я хотел бы, чтобы ES6 подходил к этой проблеме, используя фильтр / карту / уменьшение, если это возможно в этой ситуации.
  • С подходом loadash все в порядке, но я все еще хочу увидеть пример "vanilla ES6" до
  • Если я смогу получить подсказку о том, как / где лучше всего учиться, и практиковаться в фильтрации массивов всеми способами с использованием этих методов (loadash также будет крутым здесь).

Ответы [ 4 ]

6 голосов
/ 10 апреля 2019

Истинный способ FP будет reduce с повторным распространением объекта:

const filtered = Object.values(obj).reduce((p, e) => (!e.isActive ? {...p, [e.user_id]: e} : p), {});

const obj = {
    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    }, 
    112: {
        user_id: 112,
        user_name: "use112",
        isActive: 1
    }, 
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    }
};
const filtered = Object.values(obj).reduce((p, e) => (!e.isActive ? {...p, [e.user_id]: e} : p), {});
console.log(filtered);
.as-console-wrapper {
  max-height: 100% !important;
}

Это создает много ненужных временных объектов, но придерживается принципов FP (я думаю, я не "глубоко" в FP :-))изменение объектов на месте.

Немного изменив правила, мы могли бы модифицировать отдельный объект, а не создавать множество временных:

const filtered = Object.values(obj).reduce((newObj, e) => {
  if (!e.isActive) {
    newObj[e.user_id] = e;
  }
  return newObj;
}, {});

const obj = {
    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    }, 
    112: {
        user_id: 112,
        user_name: "use112",
        isActive: 1
    }, 
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    }
};
const filtered = Object.values(obj).reduce((newObj, e) => {
  if (!e.isActive) {
    newObj[e.user_id] = e;
  }
  return newObj;
}, {});
console.log(filtered);
.as-console-wrapper {
  max-height: 100% !important;
}

(Это можно записать меньшим количеством символов, если использовать оператор запятой, но это менее удобно и труднее для чтения.)

БезОграничение FP, я бы просто использовал цикл:

const filtered = {};
for (const e of Object.values(obj)) {
  if (!e.isActive) {
    filtered[e.user_id] = e;
  }
}

const obj = {
    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    }, 
    112: {
        user_id: 112,
        user_name: "use112",
        isActive: 1
    }, 
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    }
};
const filtered = {};
for (const e of Object.values(obj)) {
  if (!e.isActive) {
    filtered[e.user_id] = e;
  }
}
console.log(filtered);
.as-console-wrapper {
  max-height: 100% !important;
}
2 голосов
/ 10 апреля 2019

"Официально" предложенный способ для преобразования объекта, подобный этому, состоит в том, чтобы "линеаризовать" объект с помощью Object.entries, выполнить сопоставление / фильтр для пар ключ-значение и соединить их вместе с Object.fromEntries.Последний является новым, поэтому вам понадобится полифилл.

Пример:

// polyfill

Object.fromEntries = Object.fromEntries || function(pairs) {
    let obj = {};
    for (let [k, v] of pairs)
        obj[k] = v;
    return obj;
};


var myObj = {

    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    },
    112: {
        user_id: 112,
        user_name: "use112",
        isActive: 1
    },
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    },
};

result = Object.fromEntries(
    Object.entries(myObj)
        .filter(([k, v]) => v.isActive));

console.log(result)

Поскольку вы запросили решение FP, вот одно из возможных обобщений:

let apply = (x, fn) => fn(x);

let pipe = (...fns) => x => fns.reduce(apply, x);

let transform = fn => pipe(Object.entries, fn, Object.fromEntries);

let filter = fn => a => a.filter(fn);

let filterObject = fn => transform(filter(fn));

let removeInactive = filterObject(([k, v]) => v.isActive);

console.log(removeInactive(myObj))

FP - это выражение вашей программы в терминах композиции функций, а не о написании циклов "наизнанку" с помощью Reduce.

1 голос
/ 10 апреля 2019

Я бы использовал функцию генератора, которая принимает итерацию:

// make object type iterable

function* objEntries(o) {
  for (let k in o)
    yield [k, o[k]];
}

// generator function that takes an iterable

const itFilter = p => function* (ix) {
  for (const x of ix)
    if (p(x))
      yield x;
};

const obj = {
    111: {
        user_id: 111,
        user_name: "user111",
        isActive: 0
    }, 
    112: {
        user_id: 112,
        user_name: "use112",
        isActive: 1
    }, 
    113: {
        user_id: 113,
        user_name: "use113",
        isActive: 0
    }
};

// exhaust the iterator with a strict evaluated fold

const itFoldStrict = f => acc => ix => {
  let acc_ = acc;

  for (const x of ix)
    acc_ = f(acc_) (x);

  return acc_;
};

const ix = itFilter(([k, o]) => o.isActive === 0)
  (objEntries(obj));

// nothin has happened here due to lazy evaluation

// unleash the effect (of constructing the filtered object)

console.log(
  itFoldStrict(acc => ([k, v]) => (acc[k] = v, acc))
    ({}) (ix));

Таким образом, алгоритм

  • ленивый
  • не дает промежуточных значений
1 голос
/ 10 апреля 2019

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

var object = { 111: { user_id: 111, user_name: "user111", isActive: 0 }, 112: { user_id: 112, user_name: "use112", isActive: 1 }, 113: { user_id: 113, user_name: "use113", isActive: 0 } },
    result = Object.assign(...Object
        .entries(object)
        .filter(({ 1: { isActive } }) => isActive === 0)
        .map(([k, v]) => ({ [k]: v }))
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...