0

I have this code that the truth is repeated, it only changes the names since they do the same but the difference is that I send to call different data and I would like to reduce that code

const times = truck["Fase 1"];
const [h, m, s] = times.split(":");
const minutes = parseInt(h) * 60 + parseInt(m) + s / 60;
const time = minutes;
const color = time <= 18 ? "#0CC234" : time < 30 ? "#FACE5A" : "#FF0101";
const Fase2 = truck["Fase 2"];
console.log({ Fase2 });
const [hs, ms, ss] = Fase2.split(":");
const minutesF2 = parseInt(hs) * 60 + parseInt(ms) + ss / 60;
const time2 = minutesF2;
const colors = time2 <= 18 ? "#0CC234" : time2 < 30 ? "#FACE5A" : "#FF0101";

I feel that the code repeats itself a lot and that it can be reduced, but I don't know how

6
  • Why do you want a shorter code? Is it some kind of code golf? Commented Sep 30, 2021 at 15:57
  • 1
    You can follow DRY principles but that won't necessarily make the code shorted. In fact you might make it longer, but it would be better. Commented Sep 30, 2021 at 15:58
  • Of course, you have obvious things like, "time = minutes" that don't add anything to the code at all Commented Sep 30, 2021 at 15:59
  • If you look at fase 1 and fase 2, those two repeat themselves and repeat almost the same code in the other lines. Commented Sep 30, 2021 at 15:59
  • Will the truck object always have the same keys, such as "Fase 1", "Fase 2", etc...? And is your goal here to get the color for each truck? Commented Sep 30, 2021 at 15:59

4 Answers 4

4

You can move the repeated part to the function:

const truck = {
    'Fase 1': '11:22:33',
    'Fase 2': '11:22:33',
};

function getColor (fase) {
    const [h, m, s] = truck[fase].split(':');

    const timeInMinutes = parseInt(h) * 60 + parseInt(m) + s / 60;
    const color = timeInMinutes <= 18 ? "#0CC234" : timeInMinutes < 30 ? "#FACE5A" : "#FF0101";

    return color;
}

console.log(getColor('Fase 1'));

console.log(getColor('Fase 2'));

Sign up to request clarification or add additional context in comments.

Comments

0

There is a few unneeded variables.

const [h, m, s] = truck["Fase 1"].split(":");
const minutes = parseInt(h) * 60 + parseInt(m) + s / 60;
const color = minutes <= 18 ? "#0CC234" : minutes < 30 ? "#FACE5A" : "#FF0101";

const [hs, ms, ss] = truck["Fase 2"].split(":");
const minutesF2 = parseInt(hs) * 60 + parseInt(ms) + ss / 60;
const colors = minutesF2 <= 18 ? "#0CC234" : minutesF2 < 30 ? "#FACE5A" : "#FF0101";

Comments

0

Split out shared data into their own functions: getTime, getMinutes, and getColor. You can then access them for each truck.

function getTime(time) {
  return time.split(":");
}

function getMinutes([h, m, s]) {

  // I had to adjust this calculation so that
  // it returns a number that correlates to the
  // conditions in `getColors`
  return Math.round((parseInt(h) * 60 + parseInt(m) + parseInt(s)) / 60);
}

function getColor(minutes) {
  if (minutes <= 18) return '#0CC234';
  if (minutes <= 30) return '#FACE5A';
  return '#FF0101';
}

const time = getTime('3:45:12');
const minutes = getMinutes(time);
const color = getColor(minutes);
console.log(color)

const time2 = getTime('34:12:00');
const minutes2 = getMinutes(time2);
const color2 = getColor(minutes);
console.log(color2);

You could also use a class:

class Truck {
  
  constructor(name, time) {
    this.name = name;
    this.time = this.getTimes(time);
    this.minutes  = this.getMinutes(this.time);
    console.log(this.minutes)
    this.color = this.getColor(this.minutes);
  }
    
  getTimes(time) {
    return time.split(":");
  }

  getMinutes([h, m, s]) {
    return Math.round((parseInt(h) * 60 + parseInt(m) + parseInt(s)) / 60);
  }

  getColor() {
    if (this.minutes <= 18) return '#0CC234';
    if (this.minutes <= 30) return '#FACE5A';
    return '#FF0101';
  }  
 
}

const fase1 = new Truck('Fase1', '12:2:12');

console.log(fase1.name);
console.log(fase1.time);
console.log(fase1.minutes);
console.log(fase1.color);

5 Comments

It's just the seconds divided by 60 not the whole sum. (Or at least that was probably the intention - were you making a point about wrong precedence?)
That makes no sense. If you do that you'll get a number like 722 instead of 12 which correlates with how the colors are selected.
Now you are doing (hours * 60 + minutes + secodns) / 60; it should really better be (hours * 60 + minutes + seconds / 60)
Again: in that last example the output would be 722 not 12 which I think the OP is expecting.
Might be. For me it's just surprising to get 2 out of getMinutes(['00','59','59']) while internally it all seems to expect hours, minutes and seconds. Personally, I'd expect it to return something around 60. (Yes, 722 minutes seems to be approximately 12 hours 2 minutes and 12 seconds.)
0

Generally breaking code to small intuitively named chunks pays off in readability, maintainability and, partially, in the size of "functional part" of the code. While accepted answer demonstrates it well: it extracts core functionality to a single procedure of two function calls, for the sake of exercise, let's break the code even further, add some type definitions and check some format.

While question lacks the final step ("what is the intended product of the code") let's say we want to display each "truck fase" (probably 'track lap') times in respective colour in HTML. As seen, while the core functionality shrunk into lapDisplay(lapTitle, data) (lapDisplay function being also quite terse), sum of all utility functions grew in size considerably:

//@ts-check
"use strict";

/*
 § "The data"
 */

/**
 * @type {lapRecords}
 */
var laps = {
  "Phase 1": {
    "time": '00:15:15',
  },
  "Phase 2": {
    "time": '00:19:30',
  },
  "Phase 3": {
    "time": '00:30:23',
  }
};

/*
 § "Functionality"
*/
for (const lapTitle in laps) {
  const data = laps[lapTitle];
  const outHTML = lapDisplay(lapTitle, data);
  document.body.insertAdjacentHTML('beforeend', outHTML);
};

/*
 § "Utility Functions"
 */

/**
 * @param {string} title
 * @param {lapRecord} data
 */
function lapDisplay (title, data) {
  const duration = data.time;
  const inMinutes = durationStringToMinutes(duration);
  const colour = minutesToColour(inMinutes)
  return `<p style="color: ${colour}">
   "${title}" took ${duration}
   <small>(${inMinutes.toFixed(2)} minutes)</small>.</p>
  `;
};

/**
 * @param {number} minutes
 * @return {string} hex colour
 * @todo get ranges-colour mapping  from config object
 */
function minutesToColour (minutes) {
  if (minutes <= 18) {
    return "#0CC234";
  }
  if (minutes < 30) {
    return "#FACE5A";
  }
  return "#FF0101";
};

/**
 * @param {HoursMinutesSecondsDuration} hoursMinutesSeconds separated with colons
 */
function durationStringToMinutes (hoursMinutesSeconds) {
  if (/^[0-9]+:[0-9]+:[0-9]+$/.test(hoursMinutesSeconds) === false) {
    throw Error(`${hoursMinutesSeconds} is in wrong format.`)
  }
  let [hours,
    minutes,
    seconds] = hoursMinutesSeconds.split(":").map(_ => parseInt(_, 10));
  minutes += hours * 60;
  minutes += seconds / 60;
  return minutes
};

/*
 § Type definitions
*/
/**
 * @typedef {`${number}:${number}:${number}`} HoursMinutesSecondsDuration
 * @typedef {{"time":HoursMinutesSecondsDuration}} lapRecord
 * @typedef {Object<string,lapRecord>} lapRecords
 */

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.