【问题标题】:Nested filtering for iterative process -exponential mapping?迭代过程的嵌套过滤 - 指数映射?
【发布时间】:2020-04-18 02:21:00
【问题描述】:

让我们从简单的形式开始。 假设您有一个像这样的简单数据集:您想要检索每个资产的累积金额。

首先,我将按资产值过滤(排列)数组

  var pairs   = ["eur", "usd", "pop", "dot", "cad", "sol"];
  for(i=0; i<pairs.length; i++){
  var filtArray1  = dataArray.filter(function filt(el){return el.asset === pairs[i];});  
    filtArrays.push(filtArray1);

然后执行任何类型的操作,比如总结一下:

  var values  = Object.keys(filtArrays[i]).map(function(e){return filtArrays[i][e].amount});
  parziali.push(values);

  var somma   = values.reduce(function(acc, val) { return acc + val; }, 0);
    somme.push(somma); 

//result "somme": [9.0, 9.0, 6.0, 6.0, 9.0, 3.0]
}

好的,您可以使用indexOf(); 或任何其他更快的方法,但这不是重点。

重点是:假设我们现在向这个数据集添加了一个额外的层,一些日期字段。现在我们有:

而且,和以前一样,您希望能够检索 每个 周的 每个 资产的金额(这些是一年中的周数)..
你是怎么做到的?
它突然变成了指数。您可以使用什么类型的流程来保持迭代(即:自动)并同时减轻工作量?

此时您甚至可能想要添加额外的数据层..

如您所见,我们有两个不同的钱包,都持有欧元,但在同一周
现在我们希望能够检索每个每个资产每个每个钱包的数量。正如我所说,它有点变成指数:你是如何处理的?谢谢

ps: 数据显然之前被处理过

  for(i=0; i<data.length; i++){
    var dataRow = data[i];
    var record = {};
    record['weeks']    = dataRow[0];
    record['asset']    = dataRow[1];
    record['amount']   = dataRow[2];
    dataArray.push(record);}  

【问题讨论】:

  • 您可以利用工作表公式,特别是 QUERY 函数来提取您需要的数据。您需要了解部分实现 SQL 的 Google 的 Visualization Query Language。如果您需要使用 GAS 完成此操作,请查看以下 stackoverflow 线程:Using Bound Google Scripts to Generate a Query Object
  • 谢谢,我明天去看看
  • @DimuDesigns 感谢您的评论。我检查了它,结果证明这是我过去几天一直在寻找的东西。我已经考虑过使用 DB 方法,但我得出的结论是我只能使用这种方法:developers.google.com/apps-script/guides/…。你告诉我的实际上是缓解,因为如果我理解得很好,我可以让我的工作表成为我自己的数据库。我需要更详细地研究它,我可能会在这个小项目的第二个版本中使用它

标签: javascript arrays google-apps-script mapping filtering


【解决方案1】:

据我了解,问题不是指数级的。复杂性仍然是线性的,只是在扫描可用数据时添加更多标准。

该技术是根据您尝试分组以实现小计的字段来累积数据。例如,如果您想按年/月分组,那么只需要年/月来定义小计桶。例如,您将有一个用于“20181”、“20182”、“20183”等的存储桶。当您遍历数组中的条目时,您将使用年/月来识别存储桶并将条目值添加到那个小计桶。

如果您在小计分组中包含其他字段(例如,货币和年/月),那么只需调整存储桶名称以同时包含货币和年/月。即,您的小计桶现在将是“~cad~20181~”、“~cad~20182~”、“~eur~20181~”等。这将按货币和年/月唯一标识小计桶。然后,和以前一样,在遍历数组中的条目时,您从数组条目中获取值来识别该值所属的货币和年/月桶......请注意,波浪号是用于分隔字段的任意分隔符构造小计存储桶名称时的值。

a = [
  {geo:"cad", ym:20182, value:3},
  {geo:"eur", ym:20181, value:1},
  {geo:"pop", ym:20182, value:2},
  {geo:"usd", ym:20181, value:3},
  {geo:"cad", ym:20182, value:3},
  {geo:"sol", ym:20181, value:1},
  {geo:"cad", ym:20181, value:3},
  {geo:"pop", ym:20182, value:2},
  {geo:"pop", ym:20181, value:5}
];

 var result = a.reduce( (totals, entry) => {
   let key = '~' + entry.geo + '~' + entry.ym + '~';
   totals[key] = ( totals[key] || 0 ) + entry.value;
   return totals;
 }, {} );


console.log( result );

使用for 循环的代码变体。

arr = [
  {geo:"cad", ym:20182, value:3},
  {geo:"eur", ym:20181, value:1},
  {geo:"pop", ym:20182, value:2},
  {geo:"usd", ym:20181, value:3},
  {geo:"cad", ym:20182, value:3},
  {geo:"sol", ym:20181, value:1},
  {geo:"cad", ym:20181, value:3},
  {geo:"pop", ym:20182, value:2},
  {geo:"pop", ym:20181, value:5}
];

result = {};

// Loop through each entry in arr

for ( let i = 0; i < arr.length; i++ ) {
  
  // Create the subtotal bucket name based on the fields
  // defining the grouping.

  let key = '~' + arr[ i ].geo + '~' + arr[ i ].ym + '~';
  
  // Now that we know which subtotal bucket arr[i].value
  // belongs, let's add it to the bucket.
  result[ key ] = (result[ key ] || 0 ) + arr[ i ].value ;

}

console.log( result );

在这两个示例中,我都将值收集到一个对象中,每个属性代表一个小计存储桶。也可以使用 Map 对象,但在举例说明根据小计的分组方式命名小计桶的关键概念时不太清楚...

希望这会有所帮助。

【讨论】:

  • 如果这不是太麻烦,我有一个扩展要问你。我已经尝试过你的脚本,我非常喜欢它。它非常优雅,似乎适用于我的情况,但我正在努力理解它背后的方法。 a)您能否更深入地解释一下段落背后的逻辑,以及 b)您能否将其翻译成非箭头语法,因为 GAS 不接受它,这使我不太容易理解。例如我无法理解当我输入 totals[key] 时我到底在做什么,或者为什么即使使用 '|' 仍然可以读取 key。抱歉我还是不太流利
  • @JohnGalassi,我扩展了该方法的解释。此外,我将分隔符从“|”更改为到 '~',因为管道字符在 javascript 中用于多种用途,而我将它用作字符串分隔符可能会引起一些混乱。定义小计桶的键时分隔符的选择通常是任意的...
  • @JohnGalassi 哦,以及“为什么即使使用 '|' 键仍然可读“?对象属性名称可以包含几乎任何字符。例如,obj = {'!@#$%': 12} 是允许的,尽管您不能使用点表示法来检索对象属性。 obj.!@#$% 会抛出错误,但 obj['!@#$%'] 工作正常。
  • @JohnGalassi,我有多年的软件开发经验,所以我确信我以前遇到过这个问题的变体。另外,我发现如果我专注于问题的算法和逐步手动过程,那么只需弄清楚 javascript 必须将哪些工具应用于解决方案。很高兴我能帮上忙。
  • 可能值得将其作为另一个带有脚本详细信息的 stackoverflow 问题发布,因为目前尚不清楚这是如何发生的。
【解决方案2】:

按照 cmets 的建议,您可以使用简单的查询:

E1:

=query(A:D,"select A,B,C,sum(D) where A is not null group by A,B,C ",1)

【讨论】:

  • 感谢您的评论,但我想通过代码而不是公式来解决它;创建尽可能多的变量,涉及不同的周数。我的需要不仅仅是过滤值,而是创建不同的数据集,然后将它们写入单元格。
  • @John 查询确实会产生不同的数据,这不是简单的过滤。试试看!
猜你喜欢
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 2016-04-10
  • 2021-08-13
  • 2017-04-20
  • 2017-12-22
相关资源
最近更新 更多