Home > Mobile >  Convert arrays of active days to readable string
Convert arrays of active days to readable string

Time:10-20

I need to convert an array of boolean values indicating whether the store is open on a given day.

For example:

Case 1:

Input data: [true, true, true, true, true, true, true]
Expected output: Every day

Case 2:

Input data: [true, true, true, true, true, false, false]
Expected output: Mon-Fri

Case 3:

Input data: [true, true, false, false, true, true, true]
Expected output: Mon-Tue, Fri-Sun

Case 4:

Input data: [true, false, false, true, false, false, true]
Expected output: Mon, Thu, Sun

Case 5:

Input data: [true, true, false, true, true, true, false]
Expected output: Mon-Tue, Thu-Sat

Case 6:

Input data: [true, false, false, false, false, false, false]
Expected output: Only Monday

I came up with this, but need help with cases 2-5

const daysLabels = [
  { label: "Monday", short: "Mon" },
  { label: "Tuesday", short: "Tue" },
  { label: "Wednesday", short: "Wed" },
  { label: "Thursday", short: "Thu" },
  { label: "Friday", short: "Fri" },
  { label: "Saturday", short: "Sat" },
  { label: "Sunday", short: "Sun" }
];

const getSchedule = ({ case: days }) => {
  let activeDays = [];
  for (let i = 0; i < [...days].length; i  ) {
    const day = [...days][i];
    if (day) {
      activeDays.push({ ...daysLabels[i], value: day });
    }
  }

  if (activeDays.length === 7) {
    return "Every day";
  }

  if (activeDays.length === 1) {
    return `Only ${activeDays[0].label}`;
  }

  return "#TODO";
};

Sandbox - link

CodePudding user response:

You can use Array.reduce() to create groups of day ranges, along with the correct labels.

We then use a Array.map() call to return only the label for each range.

I've added the 6 test cases mentioned, they should all pass.

const daysLabels = [
  { label: "Monday", short: "Mon" },
  { label: "Tuesday", short: "Tue" },
  { label: "Wednesday", short: "Wed" },
  { label: "Thursday", short: "Thu" },
  { label: "Friday", short: "Fri" },
  { label: "Saturday", short: "Sat" },
  { label: "Sunday", short: "Sun" }
];

function getDayRange(input) {
    // Deal with 7 days and 1 day only first...
    if (input.filter(active => active).length === 7) { 
        return 'Every day';
    } else if (input.filter(active => active).length === 1) { 
        return `Only ${daysLabels[input.findIndex(active => active)].label}`;
    }
    // 2 - 6 days active
    return input.reduce((acc, active, idx) => {
        if (active) {
            if (!acc.length || acc[acc.length - 1].end < (idx - 1) ) { 
                acc.push({ start: idx, end: idx, label: daysLabels[idx].short, startLabel: daysLabels[idx].short });
            } else {
                acc[acc.length - 1].end = idx;
                acc[acc.length - 1].label = acc[acc.length - 1].startLabel   '-'   daysLabels[idx].short; 
            }
        }
        return acc;
    }, []).map(r => r.label).join(', ');
}

const cases = [
    { input: [true, true, true, true, true, true, true], expected: 'Every day' },
    { input: [true, true, true, true, true, false, false], expected: 'Mon-Fri' },
    { input: [true, true, false, false, true, true, true], expected: 'Mon-Tue, Fri-Sun' },
    { input: [true, false, false, true, false, false, true], expected: 'Mon, Thu, Sun' },
    { input: [true, true, false, true, true, true, false], expected: 'Mon-Tue, Thu-Sat' },
    { input: [true, false, false, false, false, false, false], expected: 'Only Monday' },
]
console.log(`Case`, '\t', 'Pass', '\t', 'Output')
cases.forEach(({ input, expected }, idx) => {
    let output = getDayRange(input);
    console.log(`${idx   1}`, '\t', output === expected, '\t', output)
})
.as-console-wrapper { max-height: 100% !important; }

CodePudding user response:

I declare a mapping array for the text, below is the example code,and you can modify the text when function return only one day or everyday.

// for index mapping
let indexMapping = [
    "Mon",
    "Tue",
    "Wed",
    "Thu",
    "Fri",
    "Sat",
    "Sun"
];
function getWeeks(arr){
    let list = [];
    let indexes = [];
    let item = [];
    // get all indexes
    arr.forEach((result,index) => {
        if(result) indexes.push(index);
    });

    // push each text to list
    indexes.map(i => {
        if(!indexes.includes(i-1)){
            if(item.length == 1){
                list.push(item[0]);
                item = [];
            }
            item.push(indexMapping[i]);
        }
        else if(!indexes.includes(i 1)){
            item.push(indexMapping[i]);
            list.push(item.join("-"));
            item = [];
        }
    });

    // if indexes only has one item
    if(item.length == 1){
        list.push(item[0]);
    }
    return list;
}

// for test
let testArr2 = [true, true, true, true, true, false, false];
let testArr3 = [true, true, false, false, true, true, true];
let testArr4 = [true, false, false, true, false, false, true];
let testArr5 = [true, true, false, true, true, true, false];
getWeeks(testArr2); // output will be like ['Mon-Fri']

CodePudding user response:

Here's my answer, This is not an optimized version.

Add below function:-

function getWeekDuration(cases) {
  let index = 0;
  let weekDurationArray = [];

  for (let i = 0; i < cases.length; i  ) {
    const day = cases[i];
    if (i === 0) {
      weekDurationArray[index] = [];
    }
    if (day) {
      weekDurationArray[index].push({ ...daysLabels[i],
        value: day
      });
    } else {
      if (weekDurationArray[index].length > 0) {
        index  = 1;
        weekDurationArray[index] = [];
      }
    }

  }

  // remove empty arrays
  weekDurationArray = weekDurationArray.filter(item => item.length > 0);

  // get only first and last day of each week duration
  weekDurationArray = weekDurationArray.map(weekDuration => {
    // concate inner array into string
    if (weekDuration.length > 1) {
      return `${weekDuration[0].short}-${weekDuration[weekDuration.length - 1].short}`;
    }
    return weekDuration[0].short;
  });

  return weekDurationArray.join(', ');

}

Add return the function from getSchedule return getWeekDuration(days);

  • Related