【问题标题】:JavaScript Best Practice Filtering Array By Three FactorsJavaScript 最佳实践通过三个因素过滤数组
【发布时间】:2020-06-07 10:01:58
【问题描述】:

我正在按照以下标准过滤一组 Vet 交易:

  • 对于一小时内的每笔交易,仅将最昂贵的交易放入结果中(交易为 {dog, timestamp, amount})
  • 如果在一小时内,同一条狗的多笔交易与最昂贵的交易并列,则仅将最早的交易放在结果中
  • 如果整个交易数组中有超过 10 条狗的交易,则不要在结果中包含来自该狗的任何交易

一小时为 00:00:00 - 00:59:59、01:00:00 - 01:59:59 等。

在降低复杂性的同时,我想提出一个遵循最佳实践的更易于阅读的解决方案。这是数据(已经按时间排序):

const dogs = [
  { "dog":"ralph", "timestamp":"2/23/2020 03:04:57", "amount": 140.00 },
  { "dog":"toto", "timestamp":"2/23/2020 03:14:31", "amount": 130.00 },
  { "dog":"toto", "timestamp":"2/23/2020 03:15:10", "amount": 145.00 },
  { "dog":"sadie", "timestamp":"2/23/2020 03:15:53", "amount": 175.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 04:05:44", "amount": 220.00 },
  { "dog":"sadie", "timestamp":"2/23/2020 05:34:41", "amount": 100.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 05:39:11", "amount": 40.00 },
  { "dog":"toto", "timestamp":"2/23/2020 05:43:00", "amount": 240.00 },
  { "dog":"toto", "timestamp":"2/23/2020 05:59:58", "amount": 235.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 06:11:52", "amount": 20.00 },
  { "dog":"toto", "timestamp":"2/23/2020 06:12:53", "amount": 90.00 },
  { "dog":"rex", "timestamp":"2/23/2020 06:12:53", "amount": 315.00 },
  { "dog":"max", "timestamp":"2/23/2020 06:12:53", "amount": 285.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 06:13:14", "amount": 240.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 07:05:21", "amount": 60.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 08:42:50", "amount": 80.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 09:07:53", "amount": 100.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 10:07:35", "amount": 200.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 11:04:20", "amount": 120.00 },
  { "dog":"bella", "timestamp":"2/23/2020 11:04:40", "amount": 160.00 },
  { "dog":"sadie", "timestamp":"2/23/2020 11:04:54", "amount": 160.00 },
  { "dog":"bella", "timestamp":"2/23/2020 11:34:33", "amount": 160.00 },
  { "dog":"bella", "timestamp":"2/23/2020 11:44:23", "amount": 160.00 },
  { "dog":"bella", "timestamp":"2/23/2020 11:48:43", "amount": 125.00 },
  { "dog":"bella", "timestamp":"2/23/2020 12:03:53", "amount": 80.00 },
  { "dog":"bella", "timestamp":"2/23/2020 12:04:03", "amount": 100.00 },
  { "dog":"bella", "timestamp":"2/23/2020 13:11:54", "amount": 125.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 14:04:35", "amount": 160.00 },
  { "dog":"bella", "timestamp":"2/23/2020 14:21:10", "amount": 170.00 },
  { "dog":"bella", "timestamp":"2/23/2020 15:15:18", "amount": 140.00 },
  { "dog":"bella", "timestamp":"2/23/2020 16:15:20", "amount": 180.00 },
  { "dog":"ralph", "timestamp":"2/23/2020 17:49:55", "amount": 180.00 }
]

这是我的工作解决方案:

function lessThanTen(dogs) {
  let count = {}
  let results = [];
  for(let i = 0; i<dogs.length; i++) {
    count[dogs[i].dog] ? count[dogs[i].dog] +=1 : count[dogs[i].dog] = 1;
  }
  for(let i = 0; i<dogs.length; i++) {
    if(!(count[dogs[i].dog] > 10)) {
      results.push(dogs[i]);
    }
  }
  return results;
}

function mostExpensive(dogs) {
  let curHour, nextHour, prevAmount, curAmount, nextAmount, highIndex;
  let results = [];
  const filtered = lessThanTen(dogs);

  filtered.forEach((click, index) => {
    curHour = filtered[index].timestamp.split(" ")[1].substring(0,2);
    curAmount = filtered[index].amount;
    if(index > 0) {
      prevAmount = filtered[index-1].amount;
    }
    if(index < filtered.length - 1) {
      nextHour = filtered[index + 1].timestamp.split(" ")[1].substring(0,2);
      nextAmount = filtered[index + 1].amount
    }
    if ((curHour === nextHour) && ((curAmount > prevAmount && curAmount > nextAmount) || (curAmount === nextAmount && !highIndex)) ) {
      highIndex = index;
    }
    if (nextHour > curHour) {
      results.push(filtered[highIndex ? highIndex : index]);
      highIndex = null;
    }
  });
  console.log(results);
}
mostExpensive(dogs);

我可以/应该将“如果在一小时内对同一只狗进行多次交易”分解为它自己的函数,以便更容易测试吗?

有没有清理forEach 中所有if 语句的好方法?我尝试了过滤和减少,但不幸的是在比较以前和当前的数量和时间时迷失了方向。

对于少于十个函数,我应该使用 for 循环以外的东西吗?这里的最佳做法是什么?我想不出避免使用两个循环 O(2n) 的方法。有什么建议吗?

一般来说,实现这三个标准的最清晰、最实用的方法是什么?

【问题讨论】:

  • 第二个标准对我来说似乎不清楚。 “在一小时内看到的每只狗”是指“在一小时内进行的每笔交易”还是“在一小时内针对特定狗的每笔交易”?条件的第二部分似乎与第一部分相矛盾。一只狗最早的交易可能不是那只狗最昂贵的交易。我在 lessThanTen 函数中发现了一个错误。它应该有&gt;= 10 而不是&gt; 10。
  • 当我使用正确的代码运行代码时,Bella 被忽略了,我得到的结果只有三个事务。我预计每个小时都有一笔交易,正确的结果应该是什么样的?
  • 谢谢 Guffa,- 三个标准是: 对于一小时内的每笔交易,只将最昂贵的交易放在结果中 如果同一条狗的多笔交易与最昂贵的交易并列一小时的时间段,只将最早的交易放在结果中如果在整个交易数组中有超过 10 条狗的交易,则不要将来自该狗的任何交易包括在结果中(因为它超过, >10 是故意的)
  • 正确的结果应该是:[ { dog: 'sadie', timestamp: '2/23/2020 03:15:53', amount: 175 }, { dog: 'toto', timestamp :'2/23/2020 05:43:00',金额:240 },{狗:'rex',时间戳:'2/23/2020 06:12:53',金额:315},{狗:'贝拉,时间戳:'2/23/2020 11:04:40',金额:160 },{狗:'贝拉',时间戳:'2/23/2020 12:04:03',金额:100}, {狗:'bella',时间戳:'2/23/2020 13:11:54',金额:125 },{狗:'bella',时间戳:'2/23/2020 14:21:10',金额:170 },{狗:'bella',时间戳:'2/23/2020 15:15:18',数量:140 }]
  • 谢谢,这样更清楚了,预期的结果真的很有用。为什么16:15:20 的交易不应该出现在结果中?我看不出它被任何标准排除在外。

标签: javascript arrays filter reduce


【解决方案1】:

少于Ten

您误用条件运算符作为 if 语句。写出来(并使用in 运算符检查狗是否在count 集合中),而是:

if (dogs[i].dog in count) {
  count[dogs[i].dog] += 1;
} else {
  count[dogs[i].dog] = 1;
}

这更清楚,但可以减少重复。您可以将条件运算符用作实际运算符来检查是否存在现有值。在局部变量中获取狗名可以使代码更短且更易读:

let dog = dogs[i].dog;
count[dog] = (dog in count ? count[dog] : 0) + 1;

不用循环往results添加项目,可以使用数组的filter方法获取狗出现十次以下的项目:

dogs.filter(item => count[item.dog] <= 10)

这将使函数:

function lessThanTen(dogs) {
  let count = {};
  for (let i = 0; i < dogs.length; i++) {
    let dog = dogs[i].dog;
    count[dog] = (dog in count ? count[dog] : 0) + 1;
  }
  return dogs.filter(item => count[item.dog] <= 10);
}

最贵

我无法真正遵循代码中的意图。似乎您正在将每个项目与上一个和下一个进行比较,但这并不能告诉您它是否是一小时内的最高值。此外,与之前的金额相比,可能来自不同的时间似乎是一个错误。

我用一种我希望易于理解的算法重写了这个函数。它只是通过与以前的最佳项目进行比较来保留它找到的最佳项目的索引。由于没有前瞻,您将在最后一小时内将最好的项目添加到循环后的结果中。

function mostExpensive(dogs) {
  const filtered = lessThanTen(dogs);

  let results = [];
  let prevHour = null, highIndex = null;

  filtered.forEach((item, index) => {
    let hour = item.timestamp.split(" ")[1].substring(0,2);
    // When the hour changes
    if (prevHour !== null && hour !== prevHour) {
      // Add best item found in previous hour
      results.push(filtered[highIndex]);
      // Reset index for the new hour
      highIndex = null;
    }
    // When first item in hour, or better than previously found
    if (highIndex === null || item.amount > filtered[highIndex].amount) {
      // Keep the index of the best item
      highIndex = index;
    }
    // Keep the hour for next iteration
    prevHour = hour;

  });
  // If there is a result from the last hour
  if (highIndex !== null) {
    // Add best item found in last hour
    results.push(filtered[highIndex]);
  }
  console.log(results);
}

【讨论】:

  • 有道理,感谢您浏览lessThanTen函数Guffa!
  • @T.Selleck:我添加了对 mostExpensive 函数的重写。
  • 有道理,感谢您通过 Guffa 发表评论!
猜你喜欢
  • 2013-02-04
  • 2014-05-23
  • 2015-11-16
  • 1970-01-01
  • 2017-08-01
  • 2014-08-01
  • 2020-08-01
  • 2019-11-30
  • 1970-01-01
相关资源
最近更新 更多