[英]Best way to group adjacent array items by value
假設我們有一組值:
[5, 5, 3, 5, 3, 3]
按價值和鄰接對它們進行分組的最佳方法是什么? 結果應如下:
[ [5,5], [3], [5], [3,3] ]
當然,我可以循環遍歷源數組並查找下一個/上一個項目,如果它們是相同的,則將它們推送到臨時數組,然后將其推送到結果數組。
但我喜歡以功能方式編寫代碼。 那么也許有更好的方法呢?
您可以使用Array.prototype.reduce
方法:
var result = [5, 5, 3, 5, 3, 3].reduce(function(prev, curr) { if (prev.length && curr === prev[prev.length - 1][0]) { prev[prev.length - 1].push(curr); } else { prev.push([curr]); } return prev; }, []); alert( JSON.stringify(result) );
如果你在談論性能 ,n - 復雜性[O(n)]就是你將得到的(你正在討論的一次迭代)。
如果您正在談論內存使用優化 ,可能您需要推送/彈出對象(而不是復制它們)。 或者嘗試在首次創建時將輸入數組組織為數組數組(例如[[5],[5],[3],[5],[3],[3]])並且只對此工作數組,將其塑造成您所瞄准的最終形式。
如果你想在實現中更加花哨,你可以嘗試實現一個遞歸函數來處理它(但作為一般的經驗法則,在兩個提供相同性能的實現之間,更容易閱讀的是一個你應該瞄准)。
我需要同樣的東西,但是按每個值的函數分組(而不是值本身)。 例如,
[1, 3, 5, 2, 4, 6, 7, 8, 9, 10, 42]
成為
[[1, 3, 5], [2, 4, 6], [7], [8], [9], [10, 42]]
給定分組功能
function (a) { return a % 2; }
一種方法是擴展@dfsq的方法,但使用按字典順序fn_prev
以避免重新計算先前的fn(val)
。
var fn_prev = null;
myArray.reduce((acc, val) => {
let fn_curr = fn(val);
if (!acc.length || fn_curr !== fn_prev) {
acc.push([val]);
} else {
acc[acc.length - 1].push(val);
}
fn_prev = fn_curr;
return acc;
}, []);
我覺得避免.reduce
更直接:
let fn_prev = null;
let acc = [];
for (let val of myArray) {
let fn_curr = fn(val);
if (!acc.length || fn_curr !== fn_prev) {
acc.push([val]);
} else {
acc[acc.length - 1].push(val);
}
fn_prev = fn_curr;
}
console.log(acc);
這可以添加到Array原型中,如下所示:
Object.defineProperty(Array.prototype, 'groupByAdjacent', {
value: function(fn) {
let fn_prev = null;
let acc = [];
for (let val of [].concat(this)) {
let fn_curr = fn(val);
if (!acc.length || fn_curr !== fn_prev) {
acc.push([val]);
} else {
acc[acc.length - 1].push(val);
}
fn_prev = fn_curr;
}
return acc;
}
});
像這樣使用:
let x = [1, 3, 5, 2, 4, 6, 7, 8, 9, 10, 42];
let grouped_x = x.groupByAdjacent(a => a % 2);
console.log(grouped_x);
對於不常見的Array.prototype.reduceRight
來說,這是一個很好的用例 -
const data = [ 5, 5, 3, 5, 3, 3 ] const groupAdjacent = (a = []) => a.reduceRight ( ([ group = [], ...result ], v) => group.length ? group[0] === v ? [ [ v, ...group ], ...result ] // v matches group : [ [ v ], group, ...result ] // v does not match group : [ [ v ], ...result ] // no group to compare , [[]] ) console.log(groupAdjacent(data)) // [ [ 5, 5 ], [ 3 ], [ 5 ], [ 3, 3 ] ] console.log(groupAdjacent([])) // [ [] ]
可以使用延續傳遞方式描述相同的過程 -
const data = [ 5, 5, 3, 5, 3, 3 ] const identity = x => x const None = Symbol () const groupAdjacent = ([ v = None, ...more ], k = identity) => v === None ? k ([[]]) : groupAdjacent (more, ([ group, ...result ]) => group.length ? group[0] === v ? k ([ [ v, ...group ], ...result ]) // v matches group : k ([ [ v ], group, ...result ]) // v does not match group : k ([ [ v ], ...result ]) // no group to compare ) console.log(groupAdjacent(data)) // [ [ 5, 5 ], [ 3 ], [ 5 ], [ 3, 3 ] ] console.log(groupAdjacent([])) // [ [] ]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.