【问题标题】:How do you convert something like 400..900 to filter values from an array of 400,500,600,700,800,900,1000如何将 400..900 之类的内容转换为从 400,500,600,700,800,900,1000 的数组中过滤值
【发布时间】:2020-12-09 20:06:10
【问题描述】:

我从 google fonts api 得到这个,所以如果你请求一种字体,你想要很多权重,你基本上可以要求 400..900。这基本上会给你从 400 到 900 的每种字体权重,或者必须写 400,500,600,700,800,900。

我想使用相同的逻辑,可以通过拆分并运行过滤循环来完成。我想知道是否有更好的方法来做到这一点。这可能更有用和更原生。我不想把它们分开。我很好奇更好的解决方案。

let a = '400..900';
a = a.split('..');
let b = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000].filter((x) => (x >= a[0] && x <= a[1]))
console.log(a,b);
// 400,500,600,700,800,900

【问题讨论】:

  • 您不应该使用&amp;&amp; 而不是|| 吗?在您的代码中 b 将包含数组中的所有元素,因为该表达式始终为真
  • 是的,谢谢。你知道更好的方法吗?
  • 不是真的,我不认为你应该在这个网站上征求意见
  • 我正在寻找解决方案,而不是意见,因为 API 很快就会变得复杂。

标签: javascript filter filtering


【解决方案1】:

您可以使用步长为 100 的 for 循环

const a = "400..900"
const [start, end] = a.split("..").map(Number)

const res = []
for (let i = start; i <= end; i += 100) {
  res.push(i)
}

console.log(res)

对于这两个数字之间的任意分隔符,您可以使用正则表达式来提取开始和结束

const a = "400---------|||||||||---------900"
const [_, start, end] = /(\d+)\D+(\d+)/.exec(a).map(Number)

const res = []
for (let i = start; i <= end; i += 100) {
  res.push(i)
}

console.log(res)

【讨论】:

  • 我想不拆分就这样做。
  • @Navanshu Rastogi hgb123 建议的是最干净的方法。分裂没什么不好
  • 如果您保证它们都存在,这将起作用。但是,如果由于某种原因并非全部都是这样的情况,那么这种方法就会遇到麻烦。
  • 是的,这也是存在的,对于每个请求,您都必须检查请求中是否有'..',这变成了 if 和 else 的长链。如果没有 .. 字符会怎么做。
  • @NavanshuRastogi 我刚刚更新了任意分隔符情况的答案
【解决方案2】:

您可以像这样以更动态的方式进行操作

const input = '400..900';
const bounds = input.split('..').map(x => parseInt(x));

const getAllInbetween = (bounds, stepSize) => {
  const steps = (bounds[1] - bounds[0]) / stepSize + 1; // Calculate how many steps are needed between the bounds

  return new Array(steps) // Create an array with the size of the amount of steps
    .fill(0) // Fill it with zeroes 
    .map((_, i) => i * stepSize + bounds[0]) // loop over it and assign the values, using the current array index
}

console.log(getAllInbetween(bounds, 100));

【讨论】:

  • 如果您保证它们都存在,这将起作用。但是,如果由于某种原因并非全部都是这样的情况,那么这种方法就会遇到麻烦。
  • 真实的声明,虽然从未提及,但有些不可能存在@samanime
【解决方案3】:

老实说,您的方式非常可靠,而我也会这样做。没有比使用过滤器更好的方法了。

如果您想让它更具可读性,您可以将拆分 a 分解为单独的变量。您还有一些额外的括号。

此外,将值列表移动到您重复使用的常量而不是每次都重新声明会有所帮助。

const values = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000];
let a = '400..900';
const [start, end] = a.split('..');
let b = values.filter(x => x >= start && x <= end)
console.log(start, end, b);

然而,所有这些都是非常非常微小的和/或只是风格上的变化。

至于不想使用split,没有办法绕过它,也没有真正的理由避免它。 split 相当快。另一种方法是使用正则表达式 (^(\d+)\.\.(\d+)$),但从性能和可读性的角度来看,我肯定会认为这更糟。

否则,如果你知道他们只会给你 3 位数的值,你可以使用 substring,但同样,这对于可读性来说更糟,如果他们给了 1000 就会搞砸。

【讨论】:

  • 我也不想使用正则表达式,它们性能不佳。我很好奇为什么 google 会选择这种方式,我猜他们的 api 已经很复杂了,他们不介意一些额外的 if。
  • 老实说,试图摆脱split 确实属于“微优化”领域,除非您需要在很短的时间内运行数万亿次这样的努力,否则真的不值得努力框架。
  • 肯定是微优化,有没有像 400..900 这样的命名法?只是好奇。
  • 不。如果您想避免拆分,您只需将它们作为两个单独的值。
【解决方案4】:

这是一种更严格的方式,使用正则表达式。

它的性能不一定更好,但我相信它更强大/更适合您的目的。

const query = '400..600';
const sizes = [400, 500, 600, 700, 800, 900, 1000];
const match = /^(([4-9]|10)00)\.\.(([4-9]|10)00)$/.exec(query);

if (!match) {
  throw "Invalid input string"
}

const offset = sizes[0]/100;
console.log(sizes.slice(+match[2] - offset, +match[4] + 1 - offset));

【讨论】:

    【解决方案5】:

    我的版本

    const a = '400..900';
    const [from,to] = a.split('..');
    const b = Array(Math.ceil((to - from + 100)/100)).fill().map((_, i) => (+from + (i*100)))
    console.log(b)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 2011-12-23
      • 2012-02-14
      • 1970-01-01
      • 2021-11-06
      • 2016-11-11
      • 1970-01-01
      相关资源
      最近更新 更多