Kayan sayıları saat ve dakika biçiminde nasıl toplayabilirim?


14

Kayan sayıları saat ve dakika biçiminde nasıl toplayabilirim?

Şunlar. bu tür iki sayıyı hesaplarsanız , 0.35+3.45= olmalıdır 4.20,3.80

var arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]
    
var sum = 0.0;
    
arr.forEach(function(item) {
  console.log(sum);
  sum += parseFloat(item);
});

Sonuç şöyle olmalıdır:

0
0.15
0.35
4.20
5.0
7.0
7.30
12.50
13.50
15.30
16.40
19.20
20.20

1
Mantığı nasıl tanımlayacaksınız?
Juhil Somaiya

6
Peki 0.2 20 dakikayı mı yoksa bir saatin 0.2'sini mi temsil ediyor? 1.0 saat demek, 0.6 saat saat demek?
Spangle

2
Maalesef 1.0, 1 saat 0 dakika anlamına mı geliyor? Örneğin 0.6 ve 0.7 ne anlama geliyor?
Pul

2
Burada bir cevap bulacaksınız: codereview.stackexchange.com/a/109478 . Sayılarınızı dizelere dönüştürün ve işlevde "."bu dizeleri bölmek için kullanın , değil ":".
Gerardo Furtado

6
Kendinizi böyle bir mantıkla karmaşık hale getiriyorsunuz. 0.5saat 30 dakika olmalı, başka bir şey tamamen mantıksız. Umarım bu gerçek hayatta bir müşteri için değildir .. Ya sabit bir zaman biriminin şamandıra değerleriyle çalışın ya da saat / dakika ayırın. Kadar basit.
Kaddath

Yanıtlar:


7

Bunun gibi "çılgın" veri formatlarıyla başa çıkmanın en iyi yolu, önce bunları aklı başında ve kolay işlenebilir bir formata dönüştürmek, dönüştürülen verileri kullanarak yapmanız gereken her şeyi yapmak ve nihayetinde (kesinlikle yapmanız gerekiyorsa) sonuçları geri dönüştürmektir. orijinal biçimi.

(Tabii ki, gerçek çözüm, bu çılgın zaman gösterimlerini tamamen kullanmayı bırakmaktır. Ancak bu her zaman pratik değildir, çünkü değiştiremeyeceğiniz eski bir sistemle arayüz kurmanız gerektiğinden.)

Sizin durumunuzda, verileriniz için uygun bir aklı başında biçim, örneğin, bir kaç dakikalık dakikalar olacaktır. Verilerinizi bu formata dönüştürdükten sonra, üzerinde normal aritmetik işlemler yapabilirsiniz.

// converts a pseudo-float of the form hh.mm into an integer number of minutes
// robust against floating-point roundoff errors, also works for negative numbers
function hhMmToMinutes(x) {
  const hhmm = Math.round(100 * x)  // convert hh.mm -> hhmm
  return 60 * Math.trunc(hhmm / 100) + (hhmm % 100)
}

// convert minutes back to hh.mm pseudo-float format
// use minutesToHhMm(minutes).toFixed(2) if you want trailing zeros
function minutesToHhMm(minutes) {
  return Math.trunc(minutes / 60) + (minutes % 60) / 100
}

const arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]

let sum = 0
console.log( arr.map(hhMmToMinutes).map(x => sum += x).map(minutesToHhMm) )

Yukarıdaki dönüşüm kodunun saat ve dakika bölümlerini ayırmadan önce giriş şamandırasını 100 ile çarptığını ve bir tam sayıya yuvarladığını unutmayın. Bu, girişleri dizgileştirme ihtiyacını ortadan kaldırırken girişleri olası yuvarlama hatalarıyla sağlam bir şekilde işlemelidir.

Burada daha fazla dikkat çekmenin nedeni, 0.01 = 1/100 sayısının (ve çoğullarının çoğunun) aslında JavaScript tarafından kullanılan ikili kayan nokta biçiminde tam olarak temsil edilememesidir . Böylece tam olarak 0,01'e eşit bir JS numarasına sahip olamazsınız - sahip olabileceğiniz en iyi şey, bir dizeye dönüştürmek hatayı otomatik olarak gizleyecek kadar yakın bir sayıdır. Ancak yuvarlama hatası hala var ve bu sayıları tam bir eşikle karşılaştırmak gibi şeyler yapmaya çalışırsanız sizi ısırır. İşte güzel ve basit bir gösteri:

console.log(Math.trunc(100 * 0.29))  // you'd think this would be 29...


7

// We got this after simple addition
// Now we want to change it into 4.2
sample = 3.8

// Now here are the minutes that the float currently shows
minutes = (sample % 1) * 100

// And the hours
hours = Math.floor(sample)

// Here are the number of hours that can be reduced from minutes
AddHours = Math.floor(minutes / 60)

// Adding them to the hours count
hours += AddHours

// Reducing mintues
minutes %= 60

// Finally formatting hour and minutes into your format
final = hours + (minutes / 100.0)
console.log(final)

Bu mantığı basit aritmetik toplama yaptıktan sonra kullanabilirsiniz, bu toplamı zaman formatına dönüştürür


2
Neden math.floor(sample/1)sadece yerine math.floor(sample)?
selbie

2
@selbie, çünkü sadece ilk olarak sample / 1 , ondalık olmadığı için JS kendisini olsa da ( sample / 1.0kullanılan JS'den beri oldukça uzun bir süre olduğu gibi;), Ama bu yüzden hızlı bir şekilde googled ve ekledim floor, kaldırmayı unuttum. Neyse bunu işaret ettiğiniz için teşekkürler
Letsintegreat

2
Bunun her element için yapılması gerektiğini belirtmelisiniz. arr sonuçta olmayan . Örneğin arr = [1.5, 2.5], sonuç 4yerine yapılacaksa4.4
Titus

1
@Titus, Evet, bu bölümü kaçırdım, bu yüzden her bir öğeden saat ve dakika getirmeliyiz, sonra bunları ayrı ayrı eklemeliyiz, o zaman sadece yaklaşımım yararlı olacaktır.
Şubat'ta

4

Javascript ES6'da uygulama. Her öğeyi döngüye aldım ve dakika, dakika dakika ayırır, dakikaların .mevcut olup olmadığını kontrol eder, aksi takdirde 0'ı toplam saat ve dakika sayın ve gerekli hesaplamayı uygulayın.

const resultObj = [0.35, 3.45].reduce((a, e) => {
  const [hours, minutes] = e.toString().split('.');
  a.h += +hours;
  a.m += (+(minutes.padEnd(2, 0)) || 0); 
  return a;
}, {h: 0, m: 0});


const result = resultObj.h + Math.floor(resultObj.m / 60) + ((resultObj.m % 60) / 100);
console.log(result);


1
Olduğu gibi çalışmaz, örneğin 0,3 solüsyonunuzla 30 dakika değil, sadece üç dakika olarak sayılır.
Spangle

3

Her şeyi saatlere veya dakikalara dönüştürmeniz ve ardından matematiği yapmanız gerekir.

Example: 0.35 + 3.45
Convert 0.35 to Hours Number((35/60).toFixed(2))
= 0.58

Then convert 3hours 45 minutes into hours
= 3 + Number((45/60).toFixed(2))
= 3hours + 0.75 hours
= 3.75

Add the 2 conversions
= 0.58 + 3.75
= 4.33 hours

Convert the 0.33 back to minutes by multiplying by 60
= 4 hours 19.8 minutes ~ 20 mins

Hope that helps!

2

Bunları önce saatlere ve dakikalara dönüştürmelisiniz

var arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4];

function add(arr) {
  var hm = arr
    .map(v => [Math.floor(v), (v % 1).toFixed(2) * 100])  // Map the array to values having [hours, minutes]
    .reduce((t, v) => { //  reduce the array of [h, m] to a single object having total hours and minutes
      t = {
        h: t.h + v[0],
        m: t.m + v[1]
      };
      return t;
    }, {
      h: 0,
      m: 0
    });

  // final result would be = 
  // total hours from above
  // + hours from total minutes (retrived using Math.floor(hm.m / 60)) 
  // + minutes (after converting it to be a decimal part)
  return (parseFloat(hm.h + Math.floor(hm.m / 60)) + parseFloat(((hm.m % 60) / 100).toFixed(2))).toFixed(2);
}

// adding `arr` array
console.log(add(arr));

// adding 0.35+3.45
console.log(add([0.35, 3.45]));


2
Ne yazık ki kimse bunu ilk başta fark etmedi. Ve muhtemelen doğru olmasına rağmen, öğrenme nereden geliyor? Çözümünüzün OP'sinden kopyalayıp yapıştırın, kısa vadede çok yardımcı olur. Ancak akıllı bir açıklamayı hak eden akıllı bir soruydu.
GetSet

2

Eğer ilk sonuç olmak istiyorum neden öğrenebilir miyim 0 ? Aşağıda bunu tek bir döngü ile yapmanın bir yoludur. Yorumlar açıklanacak kodda. Her döngüde dakikaları ekleriz ve 60'dan büyükse, bir saat ekleriz ve kalan dakikaları almak için % 60'ı kullanırız. Şamandıralar çalışmak için bir acı olabilir,

örneğin 1.1 + 2.2 === 3.3 yanlış

Bu yüzden sayıları bir dizeye ve sonra tekrar int'e dönüştürdüm.

var arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4];
let hoursTally = 0;
let minutesTally = 0;

for(var i = 0; i < arr.length; i++) {
  // Convert the float to a string, as floats can be a pain to add together
  let time = arr[i].toString().split('.');
  // Tally up the hours.
  hoursTally += parseInt(time[0]);
  // Tally up the minutes;
  let minute = time[1];
  if(minute) {
    // We do this so we add 20 minutes, not 2 minutes
    if(minute.length < 2) {
      minutesTally += parseInt(minute) * 10;
    } else {
      minutesTally += parseInt(minute);
    }
    // If the minutesTally is greater than 60, add an hour to hours
    if(minutesTally >= 60) {
      hoursTally++;
      // Set the minutesTally to be the remainder after dividing by 60
      minutesTally = minutesTally % 60;
    }
  }
  console.log(hoursTally + "." + minutesTally);
}


ah .. elbette .. 2.2 + 1.1 IS 3.3 anlamı ile 3h30min
eagle275

1
toString().split('.');- gerçekten mi?
user253751

3
@ eagle275 Fakat sayılar kayan noktalı olduğunda 1.1 + 2.2 sayısı 3.3 değil. 3.3000000000000001 veya 3.29999999999999 falan. Çünkü 1.1 gerçekten 1.1 değil ve 2.2 gerçekten 2.2 değil ve 3.3 gerçekte 3.3 değil.
user253751

tüyleri bölmeye başlamayın - Bu garip sayı şemasını baştan seçmezdim ... Programlamaya başladığımda muhtemelen her şeyi dakikalara (veya gerekirse saniyelere) dönüştürürüm - görüntüleme için geri dönüştürürüm. ama bugünlerde DateTime gözlerimde kuralları
eagle275

1

const arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]

const reducer = (acc, curr) => {
  acc = `${acc}`.split('.').length > 1 ? acc : `${acc}.0`;
  curr = `${curr}`.split('.').length > 1 ? curr : `${curr}.0`;
  let hours = parseStrAndSum(true, `${acc}`.split('.')[0], `${curr}`.split('.')[0]);
  let minute = parseStrAndSum(false, `${acc}`.split('.')[1], `${curr}`.split('.')[1]);
  hours = parseInt(hours / 1) + parseInt(minute / 60);
  minute = minute % 60;
  console.log(`${acc} + ${curr} = ${hours}.${minute}`);
  return `${hours}.${minute}`;
}

const parseStrAndSum = (is_hours, ...strs) => {
  let result = 0;
  strs.forEach(function(number) {
    if (!is_hours) {
      number = number.length == 1 ? `${number}0` : number;
    }
    result += parseInt(number);
  });
  return result;
};

arr.reduce(reducer);


1
@lan 0.15 + 0.2 Neden =0.17? Olmalıdır0.35
user12916796

1
O zaman ondalık 0.2'nin 20 dakika yerine iki dakikaya eşit olduğunu düşündüm. Şimdi kodu ayarladığım için, lütfen tekrar onaylayın.
Ian

1

Bir modülü azaltmanın standart yolu, taşma meydana geldiğinde ekleme işleminden sonra açığı eklemektir. Örneğin ikili donanım kullanarak BCD eklemeyi böyle yapardınız.

Eğer rağmen edebilirsiniz bu şekilde şamandıralar kullanılmadan ek yap, ister bir durum söz konusu olmalıdır . Temelde tamsayı miktarları üzerinde çalışmak için kayan sayıları kullanmanın problemleri iyi bilinmektedir ve burada onları yeniden şekillendirmeyeceğim.

Normal olarak, yüzdürme fraksiyonlarına ekleme 1.0 modüllü ile dolaylı olarak çalışır, kesirden taşma tam sayı kısmını arttırır. Noktayı hours.min Ayırıcı olarak yorumlarsa, kesirin 0.6'da taşmasını isteriz. Bunun için uygun zamanda 0,4 açığı gerekir.

function add_float_hours_minutes(a, b)
{
  var trial_sum = a+b;
  // did an actual overflow occur, has the integer part incremented?
  if ( Math.floor(trial_sum) > Math.floor(a)+Math.floor(b) )  {
    trial_sum += 0.4;
  }
  // has the fractional part exceeded its allotted 60 minutes?
  if ( trial_sum-Math.floor(trial_sum) >= 0.6)  {
    trial_sum += 0.4;
  }
  return trial_sum;
}

var arr = [0.15, 0.2, 3.45, 0.4, 2, 0.3, 5.2, 1, 1.4, 1.1, 2.4, 1, 3.4]

var sum = 0.0;

arr.forEach(function(item) {
  console.log(sum);
  // sum += parseFloat(item);
  sum = add_float_hours_minutes(sum, parseFloat(item));
});

Bu, OP'nin istediği şeye yuvarlayarak, aşağıdaki çıktıyı üretir

0
0.15
0.35
4.2
5.000000000000001
7.000000000000001
7.300000000000001
12.5
13.5
15.3
16.400000000000002
19.2
20.2

Son biçimlendirmeyi okuyucu için bir alıştırma olarak iki ondalık basamağa bıraktım. Tüm görkemlerindeki 15 arka basamak, şamandıra kullanmanın neden bunu yapmanın en iyi yolu olmadığını gösterir.

Ayrıca, saniye veya gün eklemek istediğinizde neler olduğunu düşünün. Kayan saniyelerin ya da bir tamsayı dizisinin oldukça standart iki yolu aniden çok daha mantıklı görünüyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.