簡體   English   中英

按值對相鄰數組項進行分組的最佳方法

[英]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.

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