Search code examples
javascriptfunctionloopsformattingstring-formatting

Format string based on number array using '-' to separate adjacent numbers and ',' for non adjacent numbers


Help me write a function that will have the following results...

  • [1,5,9] => "1,5,9"

  • [1,2,3,5] => "1-3,5"

  • [1,2,5,6] => "1-2,5-6"

  • [1,2,3,7,8,10] => "1-3,7-8,10"

  • the array will always be in ascending order.

here is the code from my use case but all my variations print incorrect results.

var testArray = [{
    book: "Genesis",
    chapter: "1",
    verse: "1"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "2"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "3"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "5"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "10"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "9"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "17"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "16"
  },
  {
    book: "Genesis",
    chapter: "1",
    verse: "18"
  },
];

function formatHandler() {
  //put the array in ascending order by verse
  const current = this.testArray.sort((a, b) => {
    return parseFloat(a.verse) - parseFloat(b.verse);
  });
  const shrtBk = current[0].book.slice(0, 3);
  let fmtdText = "";
  let i = 0;
  for (i = 0; i < current.length; i++) {
    const zero =
      typeof current[i - 1] === "undefined" ?
      Number(current[i].verse) :
      Number(current[i - 1].verse);
    const first = Number(current[i].verse);
    const second =
      typeof current[i + 1] === "undefined" ?
      -1 :
      Number(current[i + 1].verse);
    const third =
      typeof current[i + 2] === "undefined" ?
      -1 :
      Number(current[i + 2].verse);
    if (i === 0) {
      fmtdText += `${shrtBk} ${current[0].chapter}:${current[0].verse}`;
    } else if (
      second - first === 1 &&
      third - second === 1 /*&& second === not null*/
    ) {
      i++;
    } else if (
      second - first === 1 &&
      third - second !== 1 &&
      first - zero !== 1
    ) {
      fmtdText += `,${first}`;
    } else if (
      second - first === 1 &&
      third - second !== 1 /*&& second === not null*/
    ) {
      fmtdText += `-${second}`;
      i++;
    } else if (second - first !== 1) {
      fmtdText += `,${first}`;
    }
    console.log(fmtdText);
  }
}
formatHandler()


Solution

  • Ok, how about this

    function formatWithRanges(ary) {
        let res = [],
            last = null
    
        for (let x of ary) {
            if (last && last[1] + 1 === x)
                last[1]++
            else
                res.push(last = [x, x])
        }
    
        return res
            .map(r => r[0] === r[1] ? r[0] : r[0] + '-' + r[1])
            .join(',')
    }
    
    console.log(formatWithRanges([1, 5, 9]))
    console.log(formatWithRanges([1, 2, 3, 5]))
    console.log(formatWithRanges([1, 2, 5, 6]))
    console.log(formatWithRanges([1, 2, 3, 7, 8, 10]))