if数组返回0值所需的后备值

时间:2018-10-09 11:51:20

标签: javascript arrays lodash

我正在为图形输出的基数计算最小值。我的一个数组输出的值为零,因此不符合要求,并返回undefined。

const data =  [
    {value:0},
    {value:0},
    {value:0} ];

const defaultMinThreshold = 0;

const minThreshold = _.min([parseFloat(_.minBy(_(data).filter(d => d.value > 0).value(), 'value').value) - 0.5, defaultMinThreshold]);

如果数据的值大于0,例如

const data =  [
    {value:1},
    {value:0},
    {value:0} ];

这返回minThreshold作为0-这是预期的。当/如果所有值均为0时,我需要它返回0而不是返回未定义。

我需要添加一个条件,即在数据中搜索至少具有大于0的1个值的值,否则默认返回0。

JS小提琴-https://jsfiddle.net/0cps7q9j/

nb如您所见,我确实将值过滤为> 0,我可以做一个>= 0,但是对于在该数据集中可能为零的数组,这会将基数降低为0,因此无法更改。

过滤器的原因是数据是否具有

const data =  [
        {value:4},
        {value:4},
        {value:3} ];

高于最小值将返回3,因此阈值将为3,并且图形将从3开始而不是零。

4 个答案:

答案 0 :(得分:1)

如果您不必完全使用Lodash,则这里的内容实用且易读。如果愿意,您也可以将其转换为纯Lodash解决方案。

https://jsfiddle.net/0cps7q9j/11/

const data =  [
    {value:-1},
    {value:'0'},
    {value:1.234} ];

const defaultMinThreshold = 0;

  const filteredDataValueArray = data.filter(obj => !isNaN(parseFloat(obj.value)) && parseFloat(obj.value) >= 0).map(obj => obj.value);

    const minThreshold = _.min(filteredDataValueArray) || defaultMinThreshold;

console.log('filteredDataValueArray', filteredDataValueArray);
console.log('minThreshold', minThreshold);

答案 1 :(得分:1)

我认为,这样编写代码将更容易理解:

const values = data.map(d => d.value);
const hasNonZero = values.some(v => v > 0);
const minThreshold = hasNonZero ? _.min(values) : 0;

我只在_.min中使用lodash,这在这里很方便。您也可以将其替换为Math.min(...values)Math.min.apply(null, values)


测试

const dataSets = [
  [
   { value: 0 },
   { value: 0 },
   { value: 0 }
  ],
  [
   { value: 1 },
   { value: 0 },
   { value: 0 }
  ],
  [
   { value: 4 },
   { value: 4 },
   { value: 3 }
  ]
];

function getMinThreshold(data) {
  const values = data.map(d => d.value);
  const hasNonZero = values.some(v => v > 0);
  const minThreshold = hasNonZero ? Math.min(...values) : 0;
  return minThreshold;
}

dataSets.forEach(data => console.log(getMinThreshold(data)))

答案 2 :(得分:0)

让我们打破逻辑,以更好地呈现正在发生的事情。我已经提取了代码,并在单独的行中分解了每个操作,因此更容易看到:

const data =  [
    {value:0},
    {value:0},
    {value:0} ];

const defaultMinThreshold = 0;

const filterResult = _(data).filter(d => d.value > 0).value();
const minByResult = _.minBy(filterResult, 'value');
const minValue = minByResult.value;
const parsedValue = parseFloat(minValue);
const processedValue = parsedValue - 0.5;
const pair = [processedValue, defaultMinThreshold]

const minThreshold = _.min(pair);

首先,我将解决一些问题,并讨论一些可以简化的过程。


_(data).filter(d => d.value > 0).value()

这有点不必要,也与lodash的其他调用不一致。最好这样做_.filter(data, d => d.value > 0)-既简短又一致。


const filterResult = _(data).filter(d => d.value > 0).value();
const minByResult = _.minBy(filterResult, 'value');
const minValue = minByResult.value;

所有三行仅与value属性一起使用,并最终从中提取数字。由于不需要继续处理对象,因此可以提取value并直接使用它。整个部分变成

const mapResult = _.map(data, 'value');
const filterResult = _.filter(mapResult, d => d > 0);
const minValue = _.min(filterResult);

另外,整个问题出在minValue上-如果您有一个空数组,并尝试在其上使用_.min_.minBy,则会得到undefined。我会回到那。


const parsedValue = parseFloat(minValue);

这是不必要的。 minValue已经是一个数字。 JS有一个单一的数字类型,它已经是浮点型的-从整数到浮点型没有“强制转换”,反之亦然。因此,无需解析。整行都可以删除。


const processedValue = minValue - 0.5;

因此,知道minValue可以为undefined,可以在此处进行一些修改。您可以使用三元数undefined来检查minValue ? minValue : 0 - 0.5,但我发现始终确保您从_.min返回一个数字比较容易,即使它试图处理一个空数组也是如此。

const minValue = _.min(filterResult) || 0; //if the first value is falsey (undefined), return zero
const processedValue = minValue - 0.5; //you might end up with a result of -0.5
const clampedValue = _.clamp(processedValue, 0, Infinity); //ensures the value is [0,) - zero (inclusive) to unbound maxiumum

将所有内容放在一起

const data =  [
    {value:0},
    {value:0},
    {value:0} ];

const defaultMinThreshold = 0;

const mapResult = _.map(data, 'value');
const filterResult = _.filter(mapResult, d => d > 0);
const minValue = _.min(filterResult) || 0;
const processedValue = minValue - 0.5;
const clampedValue = _.clamp(processedValue, 0, Infinity);
const pair = [clampedValue, defaultMinThreshold];

const minThreshold = _.min(pair);

console.log(minThreshold)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

这有点冗长,仅使用许多变量将它们传递给下一个函数。您可以通过几种方法将其删除。第一种选择是使用chaining

const data =  [
    {value:0},
    {value:0},
    {value:0} ];

const defaultMinThreshold = 0;

var processedValue = _.chain(data)
  .map('value')
  .filter(d => d > 0)
  .sort()
  .take(1) //min() breaks the array chaining, so doing sort() -> take(1) ensures we can continue
  .map(x => x - 0.5) //not checking for "undefined" because an empty array won't be further processed
  .map(_.clamp) //the second and third argument to _clamp are optional and omitting them is the same as passing 0 and Infinity
  .value()[0];

//this will be undefined because we're getting index zero of an empty array
console.log("processedValue", processedValue); 

const pair = [processedValue, defaultMinThreshold];

//the minimum of undefined and zero is zero. So you don't need extra checks
const minThreshold = _.min(pair);

console.log("minThreshold", minThreshold)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>

我以这种方法离开了clamp,但是可能不需要它。由于零数组是自动处理的,因此得到小于零的结果的唯一方法是,如果最小值为0.3,那么当从中减去0.5时,结果将是负数。如果这不是可能的输入,则可以省略clamp

以上内容将始终在数组上运行,直到完成并获取值为止。一种替代方法是实际使用.min(),正如我提到的那样,它会中断数组链接,因为它返回单个值。这意味着您无法再使用.map(),我个人认为这有点不一致。只是为了说明然后发生的事情,这里是如何对单个值进行运算。

const data =  [
    {value:0},
    {value:0},
    {value:0} ];

const defaultMinThreshold = 0;

var processedValue = _.chain(data)
  .map('value')
  .filter(d => d > 0)
  .min()
  .thru(x => x - 0.5) //if using .min() then you can use .thru to manipulate the single value
  .thru(_.clamp)
  .value();

//in this case, we get NaN because of undefined - 0.5
console.log("processedValue", processedValue); 

const pair = [processedValue, defaultMinThreshold];

//the minimum of NaN and zero is still zero
const minThreshold = _.min(pair);

console.log("minThreshold", minThreshold)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.11/lodash.min.js"></script>


另一种实现此目的的方法是对函数进行处理,而不是像_.chain那样每次都对值进行操作。为简便起见,这使用functional form of Lodash,但是如果您通过_.rearg_.curry传递函数,则可以使用普通的Lodash。无论如何,这是什么样子:

const data =  [
    {value:0},
    {value:0},
    {value:0} ];

const defaultMinThreshold = 0;

const processChain = _.flow( //compose all functions together
        _.map('value'),
        _.filter(d => d > 0),
        _.min,
        x => x || 0,
        x => x - 0.5,
        _.clamp(0)(Infinity)
      );

const processedValue = processChain(data);

console.log("processedValue", processedValue)

const pair = [processedValue, defaultMinThreshold];

const minThreshold = _.min(pair);

console.log("minThreshold", minThreshold)
<script src="https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)"></script>

实际上,这与您的代码如何工作以及我的最初故障非常接近。 _.flow的工作方式实质上是完成以下

aResult = a(input);
bResult = b(aResult)
cResult = c(bResult)

,依此类推,除了它定义了 process 之外,您可以在以后提供input,然后依次传递。

答案 3 :(得分:0)

使用_.minBy使用lodash的简洁方法:

const data = [ [ { value: 0 }, { value: 0 }, { value: 0 } ], [ { value: 1 }, { value: 0 }, { value: 0 } ], [ { value: 4 }, { value: 4 }, { value: 3 } ] ];

const result = _.map(data, x => _.minBy(x, 'value').value)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>