Можно ли вернуть сравниваемое значение + строку из троичной операции без повторения указанного значения? - PullRequest
4 голосов
/ 26 марта 2019

Я пытаюсь найти более простое решение проблемы.

Проблема:

Я хочу попытаться упростить это, но понятия не имею, с чего начать.

let days = Math.floor(distance / (1000 * 60 * 60 * 24));
if(days > 0) {
    days = days + "d";
}

Попытка:

Я думал, что мог бы использовать троичные операторы, чтобы вернуть вычисление + "d" примерно так:

let days = Math.floor(distance / (1000 * 60 * 60 * 24)) === 0 ? Math.floor(distance / (1000 * 60 * 60 * 24)) + "d" : "";

это, однако, очень грязно, на мой взгляд иЯ не могу найти другой способ.

Текущая структура

В настоящее время я рассчитываю дни, часы, минуты и секунды для такого таймера:

let distance = expiry - now;
let days = Math.floor(distance / (1000 * 60 * 60 * 24));
let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
let seconds = Math.floor((distance % (1000 * 60)) / 1000);

Послечто я хочу показывать только дни, если это greater than 0 или минуты, если это greater than 0 и так далее.В настоящее время я делаю это с кучей операторов if и логическим значением, чтобы проверить, было ли уже найдено значение больше 0.Вот так:

let isSet = false;

if (days > 0 && !isSet) {
    current = days + "d";
    isSet = true;
}

if (hours > 0 && !isSet) {
    current = hours + "h";
    isSet = true;
}

if (minutes > 0 && !isSet) {
    current = minutes + "m";
    isSet = true;
}

if (seconds > 0 && !isSet) {
    current = seconds + "s";
    isSet = true;
}

if (seconds < 0 && !isSet) {
    current = "expired";
    isSet = true;
}

Это, однако, кажется очень повторяющимся и неправильным (даже если это работает).

Ответы [ 7 ]

5 голосов
/ 26 марта 2019

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

var ranges = [
    [86400000, 'd'],
    [3600000, 'h'],
    [60000, 'm'],
    [1000, 's'],
]

Затем выполните цикл по этому массиву и проверьте,предоставленное значение больше текущего периода.

function humanDiff(milliseconds) {
    for (var i = 0; i < ranges.length; i++) {
        if (milliseconds >= ranges[i][0]) {
            return Math.round((milliseconds / ranges[i][0])) + ranges[i][1]
        };
    }
    return milliseconds;
}

Пример:

var expiry = new Date('2019-03-26 08:29');
var now = new Date('2019-03-26 05:00');
humanDiff(expiry - now) // 3h

Преимущества:

  • Избегайте ненужных вычислений (не рассчитывайте часы иминуты, когда подходящие дни)
  • Избегать повторения кода
  • Отделить настройку от выполнения (добавить больше метрик так же просто, как добавить новую запись в массив диапазонов)
1 голос
/ 26 марта 2019

Вместо хранения информации в качестве переменных вы можете сохранить их как свойства объекта.Затем вы можете перебирать каждое свойство и просто устанавливать желаемый текст.

const dateInfo = {
  days: 1E3 * 60 * 60 * 24,
  hours: 1E3 * 60 * 60,
  minutes: 1E3 * 60,
  seconds: 1E3
};

function check(distance) {
  return Object.keys(dateInfo).reduce(function(result, key) {
    result[key] = Math.floor(distance / dateInfo[key]);
    distance -= dateInfo[key] * result[key];
    result[key] = result[key] > 0 ? `${result[key]}${key}` : "";
    return result;
  }, {});
}

let result = check(1E9);
console.log(result); // result
console.log(Object.values(result).join(" ")); // Print all properties
console.log(Object.values(result).find(item => item) || "Expired"); // Print first property

Самый эффективный и компактный способ:

const dateInfo = {
  d: 1E3 * 60 * 60 * 24,
  h: 1E3 * 60 * 60,
  m: 1E3 * 60,
  s: 1E3
};

function check(distance) {
  // Find the biggest proprty that is still smaller than the total difference
  var key = Object.keys(dateInfo).find(key => dateInfo[key] <= distance);
  // No need for % since distance > dateInfo[key]
  return `${Math.floor(distance / dateInfo[key]) || "expired"}${key || ""}`;
}

console.log(check(3E9)); //34d
console.log(check(3E7)); //8h
console.log(check(3E5)); //5m
console.log(check(3E3)); //3s
console.log(check(3E0)); //expired
0 голосов
/ 26 марта 2019

Метод водопада, такой как у вас, не плохая идея.Я бы изменил его, чтобы обновить переменную расстояния при добавлении в строку, например, такую ​​(например, 4d 3h 17m 1s):

function formatDuration (seconds) {
    let s = seconds, r = '', t;

    if (s % 86400 !== s) updateR('d', 86400);
    if (s % 3600 !== s) updateR('h', 3600);
    if (s % 60 !== s) updateR('m', 60);
    if (s > 0) updateR('s', 1);

    function updateR(unit, n) {
        t = Math.floor(s / n);
        s %= n;
        r += (r === '' ? '' : ' ') + t + unit;
    }

    return r.replace(/,\s(?=\d{1,2}\s\w+$)/, ' and ') || 'expired';
}

и более выразительную версию (например, 4 days, 3 hours, 17 minutes, and 1 second):

function formatDuration (seconds) {
    let s = seconds, r = '', t;

    // if (s % 31536000 !== s) updateR(' year', 31536000);
    if (s % 86400 !== s) updateR(' day', 86400);
    if (s % 3600 !== s) updateR(' hour', 3600);
    if (s % 60 !== s) updateR(' minute', 60);
    if (s > 0) updateR(' second', 1);

    function updateR(unit, n) {
        t = Math.floor(s / n);
        s %= n;
        r += (r === '' ? '' : ', ') + t + unit + (t === 1 ? '' : 's');
    }

    return r.replace(/,\s(?=\d{1,2}\s\w+$)/, ' and ') || 'expired';
}
0 голосов
/ 26 марта 2019

Вы можете взять массив значений, и если вы найдете индекс, возьмите этот индекс в качестве средства доступа для значения и постфикса или 'expired' в качестве значения.

let distance = expiry - now,
    factors = [86400000, 3600000, 60000, 1000],
    values = factors.map(f => [Math.floor(distance / f), distance %= f][0]),
    index = values.findIndex(v => v > 0),
    result = index === -1 ? 'expired' : value[index] + 'DHMS'[index];

console.log(result);
0 голосов
/ 26 марта 2019
getDurationDetails:function(duration){
            var result = [];
            var units = {
                    Year:31536000,
                    Month:2592000,
                    Week:604800,
                    Day: 86400,
                    Hour: 3600,
                    Minute: 60,
                    Second:1,
            };

            for(var name in units) {
                var res =  Math.floor(duration/units[name]);
                if(res == 1) result.push(" " + res + " " + name);
                if(res >= 2) result.push(" " + res + " " + name + "s");
                duration %= units[name];
            }
            return result;
        },

попробуйте это

0 голосов
/ 26 марта 2019

Ваша самая большая проблема - это переменная isSet, а не то, что вы используете оператор if.

Вместо установки isSet, вы должны просто использовать else:

var current;
if (days > 0) {
    current = days + "d";
} else if (hours > 0) {
    current = hours + "h";
} else if (minutes > 0) {
    current = minutes + "m";
} else if (seconds > 0) {
    current = seconds + "s";
} else if (seconds < 0) {
    current = "expired";
} // else seconds == 0

Вы можете использовать условные операторы здесь.Вы не должны пытаться объединить их в вычислении days = Math.floor(distance / (1000 * 60 * 60 * 24)), оставьте это как есть - days это просто временная переменная.Сохраните результат условия в другой переменной (current), а не в days:

const distance = expiry - now;
const days = Math.floor(distance / (1000 * 60 * 60 * 24));
const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((distance % (1000 * 60)) / 1000);

const current =
  (days > 0) ? days + "d" :
  (hours > 0) ? hours + "h" :
  (minutes > 0) ? minutes + "m" :
  (seconds > 0) ? seconds + "s" :
//(seconds == 0) ? undefined :
  "expired";
0 голосов
/ 26 марта 2019

Вы можете использовать условный спред

const now = new Date(2018, 1, 5, 10, 11);
const expiry = new Date(2018, 2, 5, 5, 6);

let distance = expiry - now;
let days = Math.floor(distance / (1000 * 60 * 60 * 24));
let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
let seconds = Math.floor((distance % (1000 * 60)) / 1000);

const arr = [
  ...(days > 0 ? [days + "d"] : []),
  ...(hours > 0 ? [hours + "h"] : []),
  ...(minutes > 0 ? [minutes + "m"] : []),
  ...(seconds > 0 ? [seconds + "s"] : []),
];

const current = arr.length ? arr.join(' ') : "expired";

console.log(current);
...