Требуется запасное значение, если массив возвращает 0 значений - PullRequest
0 голосов
/ 09 октября 2018

Я рассчитываю минимальное значение для основы вывода графика.Один из моих массивов выводит нулевое значение, таким образом не удовлетворяя требованию и возвращая неопределенное значение.

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.

Мне нужно поставить условное выражение, которое ищет данные для значений, которые по крайней мере имеют 1 значение больше 0иначе возвращает 0 по умолчанию.

JS Fiddle - https://jsfiddle.net/0cps7q9j/

nb Как вы видите, я фильтрую значения, чтобы они были > 0, я мог бы сделать >= 0, но это снижаетбаза в 0 для массивов, которые могут иметь нулевое значение в этом наборе данных, поэтому не могут изменить это.

Причина фильтра - если данные имели значения

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

Свыше минимального значения вернет 3, поэтому порог будет 3, а график будет начинаться с 3, а не с нуля.

Ответы [ 4 ]

0 голосов
/ 09 октября 2018

Краткий способ с lodash с использованием _.minBy:

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>
0 голосов
/ 09 октября 2018

На мой взгляд, ваш код будет легче понять, написав это так:

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

Я использую только lodash для _.min, что здесь удобно.Вы также можете заменить это на 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)))
0 голосов
/ 09 октября 2018

Давайте разберем логику, чтобы лучше представить, что происходит.Я извлек код и разбил каждую операцию на отдельной строке, чтобы было легче увидеть:

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>

Это немного многословно и использует много переменных только для передачи их следующей функции.Вы можете вырезать их несколькими способами.Первый вариант - использование цепочка

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.При этом для краткости используется функциональная форма Lodash , но вы можете использовать обычный Lodash, если передаете функции через _.rearg и _.curry.В любом случае, вот как это выглядит:

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)

и т. Д., За исключением того, что он определяет процесс , затем вы можете позже предоставить input, который будет, в свою очередь, впоследствии будет передан.

0 голосов
/ 09 октября 2018

Если вам не нужно полностью использовать 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);
...