簡體   English   中英

我如何`.filter()`一個數組/對象並返回一個帶有原始鍵的新數組,而不是作為一個索引數組/對象作為過濾器返回?

[英]How do I `.filter()` an array/object and return a new array with the original keys and not as an indexed array/object as filter return?

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時,將鍵設置為相同(等於用戶ID):

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)));

返回索引鍵

  • 沒有for循環(除非必須使用ES6 .forEach() )。
  • 我希望在這種情況下使用filter / map / reduce來解決此問題的ES6方法。
  • loadash方法還可以,但我仍然想在之前看到一個“香草ES6”示例
  • 如果我能獲得使用這些方法以各種方式最好地學習和練習如何過濾陣列的技巧(在這里,loadash也會很酷)。

真正的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; } 

進行此類對象轉換的“正式”建議方法是使用Object.entries對對象進行“線性化”,對鍵值對執行映射/過濾,然后將它們與Object.fromEntries放回原處。 后者是新的,因此您需要一個polyfill。

例:

 // 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編寫“由內而外”的循環。

您可以獲取條目,過濾並構建新對象。

 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; } 

我會使用一個可迭代的生成器函數:

 // 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)); 

這樣的算法

  • 不產生中間值

以下工作也很好:

var newObj = Object.entries(obj).filter(value => {return value[1].isActive ===0});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM