David Gordon
David Gordon

Reputation: 21

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...

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()

Upvotes: 1

Views: 49

Answers (2)

AlexSp3
AlexSp3

Reputation: 2293

Use .map() to modify the array and put a "-" or a "," depends on the following number. Then, take a substring to erase the last ",":

function range(a) {

  const s = a.map((e, i) => {
      if (e + 1 === a[i + 1]) {
         if (e - 1 !== a[i - 1]) 
           return e + "-";
      } else return e + ","; 
  }).join("");

  return s.substring(0, s.length - 1);
}

console.log(range([1, 5, 9]))
console.log(range([1, 2, 3, 5]))
console.log(range([1, 2, 5, 6]))
console.log(range([1, 2, 3, 7, 8, 10]))

Upvotes: 0

georg
georg

Reputation: 214959

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]))

Upvotes: 2

Related Questions