Saya memiliki array Javascript yang ingin saya bagi menjadi dua berdasarkan apakah fungsi yang dipanggil pada setiap elemen kembali true
atau false
. Pada dasarnya, ini adalah array.filter
, tapi saya ingin juga ada di tangan unsur-unsur yang disaring keluar .
Saat ini, rencana saya adalah menggunakan array.forEach
dan memanggil fungsi predikat pada setiap elemen. Bergantung pada apakah ini benar atau salah, saya akan mendorong elemen saat ini ke salah satu dari dua larik baru. Apakah ada cara yang lebih elegan atau lebih baik untuk melakukan ini? Di array.filter
mana kemauan mendorong elemen ke array lain sebelum kembali false
, misalnya?
javascript
Mike Chen
sumber
sumber
.filter
tetapi efek samping seperti itu sulit dilacak dan dipahami. Lakukan iterasi pada array dan dorong ke satu array atau lainnya.Jawaban:
Dengan ES6 Anda dapat menggunakan sintaks spread dengan mengurangi:
function partition(array, isValid) { return array.reduce(([pass, fail], elem) => { return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]]; }, [[], []]); } const [pass, fail] = partition(myArray, (e) => e > 5);
Atau dalam satu baris:
const [pass, fail] = a.reduce(([p, f], e) => (e > 5 ? [[...p, e], f] : [p, [...f, e]]), [[], []]);
sumber
Anda dapat menggunakan lodash.partition
var users = [ { 'user': 'barney', 'age': 36, 'active': false }, { 'user': 'fred', 'age': 40, 'active': true }, { 'user': 'pebbles', 'age': 1, 'active': false } ]; _.partition(users, function(o) { return o.active; }); // → objects for [['fred'], ['barney', 'pebbles']] // The `_.matches` iteratee shorthand. _.partition(users, { 'age': 1, 'active': false }); // → objects for [['pebbles'], ['barney', 'fred']] // The `_.matchesProperty` iteratee shorthand. _.partition(users, ['active', false]); // → objects for [['barney', 'pebbles'], ['fred']] // The `_.property` iteratee shorthand. _.partition(users, 'active'); // → objects for [['fred'], ['barney', 'pebbles']]
atau ramda.partition
R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']); // => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ] R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' }); // => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ]
sumber
Anda dapat menggunakan pengurangan untuk itu:
function partition(array, callback){ return array.reduce(function(result, element, i) { callback(element, i, array) ? result[0].push(element) : result[1].push(element); return result; }, [[],[]] ); };
Memperbarui. Menggunakan sintaks ES6, Anda juga dapat melakukannya menggunakan rekursi:
function partition([current, ...tail], f, [left, right] = [[], []]) { if(current === undefined) { return [left, right]; } if(f(current)) { return partition(tail, f, [[...left, current], right]); } return partition(tail, f, [left, [...right, current]]); }
sumber
[...left, current]
atau[...right, current]
- untuk setiap elemen. Saya tidak tahu internal persisnya, tetapi saya yakin bahwa konstruksinya lebih mahal daripada sekadar mendorong elemen ke array. Selain itu, sebagai aturan umum, rekursi lebih mahal daripada iterasi , karena melibatkan pembuatan "bingkai tumpukan" setiap kali.Ini terdengar sangat mirip dengan metode Ruby
Enumerable#partition
.Jika fungsi tidak dapat memiliki efek samping (yaitu, tidak dapat mengubah array asli), maka tidak ada cara yang lebih efisien untuk mempartisi array daripada mengulang setiap elemen dan mendorong elemen tersebut ke salah satu dari dua array Anda.
Karena itu, membuat metode
Array
untuk menjalankan fungsi ini bisa dibilang lebih "elegan" . Dalam contoh ini, fungsi filter dijalankan dalam konteks array asli (yaitu,this
akan menjadi array asli), dan menerima elemen dan indeks elemen sebagai argumen (mirip dengan metode jQueryeach
):Array.prototype.partition = function (f){ var matched = [], unmatched = [], i = 0, j = this.length; for (; i < j; i++){ (f.call(this, this[i], i) ? matched : unmatched).push(this[i]); } return [matched, unmatched]; }; console.log([1, 2, 3, 4, 5].partition(function (n, i){ return n % 2 == 0; })); //=> [ [ 2, 4 ], [ 1, 3, 5 ] ]
sumber
Saya datang dengan pria kecil ini. Ini digunakan untuk setiap dan semua yang seperti yang Anda jelaskan, tetapi terlihat bersih dan ringkas menurut saya.
//Partition function function partition(array, filter) { let pass = [], fail = []; array.forEach((e, idx, arr) => (filter(e, idx, arr) ? pass : fail).push(e)); return [pass, fail]; } //Run it with some dummy data and filter const [lessThan5, greaterThanEqual5] = partition([0,1,4,3,5,7,9,2,4,6,8,9,0,1,2,4,6], e => e < 5); //Output console.log(lessThan5); console.log(greaterThanEqual5);
sumber
for
loop sederhana seperti dalam jawaban lama oleh @qwertymk. Misalnya untuk sebuah array yang berisi 100.000 elemen, itu dua kali lebih lambat di sistem saya.Dalam fungsi filter, Anda dapat mendorong item palsu Anda ke variabel lain di luar fungsi:
var bad = [], good = [1,2,3,4,5]; good = good.filter(function (value) { if (value === false) { bad.push(value) } else { return true});
Tentu saja
value === false
perlu perbandingan nyata;)Tapi itu melakukan operasi yang hampir sama seperti
forEach
. Saya pikir Anda harus menggunakanforEach
pembacaan kode yang lebih baik.sumber
Mudah dibaca.
const partition = (arr, condition) => { const trues = arr.filter(el => condition(el)); const falses = arr.filter(el => !condition(el)); return [trues, falses]; }; // sample usage const nums = [1,2,3,4,5,6,7] const [evens, odds] = partition(nums, (el) => el%2 == 0)
sumber
Coba ini:
function filter(a, fun) { var ret = { good: [], bad: [] }; for (var i = 0; i < a.length; i++) if (fun(a[i]) ret.good.push(a[i]); else ret.bad.push(a[i]); return ret; }
DEMO
sumber
Bagaimana dengan ini?
[1,4,3,5,3,2].reduce( (s, x) => { s[ x > 3 ].push(x); return s;} , {true: [], false:[]} )
Mungkin ini lebih efisien daripada operator penyebaran
Atau sedikit lebih pendek, tapi lebih jelek
[1,4,3,5,3,2].reduce( (s, x) => s[ x > 3 ].push(x)?s:s , {true: [], false:[]} )
sumber
Banyak jawaban di sini digunakan
Array.prototype.reduce
untuk membangun akumulator yang bisa berubah, dan dengan tepat menunjukkan bahwa untuk larik yang besar, ini lebih efisien daripada, katakanlah, menggunakan operator penyebaran untuk menyalin larik baru setiap iterasi. Sisi negatifnya adalah bahwa ini tidak secantik ekspresi "murni" yang menggunakan sintaks lambda pendek.Tapi jalan keluarnya adalah dengan menggunakan operator koma. Dalam bahasa mirip C, koma adalah operator yang selalu mengembalikan operan tangan kanan. Anda dapat menggunakan ini untuk membuat ekspresi yang memanggil fungsi void dan mengembalikan nilai.
function partition(array, predicate) { return array.reduce((acc, item) => predicate(item) ? (acc[0].push(item), acc) : (acc[1].push(item), acc), [[], []]); }
Jika Anda memanfaatkan fakta bahwa ekspresi boolean secara implisit diubah menjadi angka 0 dan 1, dan Anda dapat membuatnya lebih ringkas, meskipun menurut saya tidak dapat dibaca:
function partition(array, predicate) { return array.reduce((acc, item) => (acc[+!predicate(item)].push(item), acc), [[], []]); }
Pemakaian:
const [trues, falses] = partition(['aardvark', 'cat', 'apple'], i => i.startsWith('a')); console.log(trues); // ['aardvark', 'apple'] console.log(falses); // ['cat']
sumber
Partisi ONE-LINER
const partition = (a,f)=>a.reduce((p,q)=>(p[+!f(q)].push(q),p),[[],[]]);
DEMO
// to make it consistent to filter pass index and array as arguments const partition = (a, f) => a.reduce((p, q, i, ar) => (p[+!f(q, i, ar)].push(q), p), [[], []]); console.log(partition([1, 2, 3, 4, 5], x => x % 2 === 0)); console.log(partition([..."ABCD"], (x, i) => i % 2 === 0));
Untuk Ketikan
const partition = <T>( a: T[], f: (v: T, i?: number, ar?: T[]) => boolean ): [T[], T[]] => a.reduce((p, q, i, ar) => (p[+!f(q, i, ar)].push(q), p), [[], []]);
sumber
.push
parameterq
: "Argumen tipe 'T' tidak dapat ditetapkan ke parameter jenis 'never'.ts (2345)"Saya akhirnya melakukan ini karena mudah dimengerti (dan sepenuhnya diketik dengan skrip ketikan).
const partition = <T>(array: T[], isValid: (element: T) => boolean): [T[], T[]] => { const pass: T[] = [] const fail: T[] = [] array.forEach(element => { if (isValid(element)) { pass.push(element) } else { fail.push(element) } }) return [pass, fail] } // usage const [pass, fail] = partition([1, 2, 3, 4, 5], (element: number) => element > 3)
sumber