'Is there a more functional way to merge and foreach/sort two arrays in TypeScript, React?

I'm learning React and TypeScript. For sake of practise, I've tried to create a calculator design by merging two arrays to map a single array onto the grid (display: grid; grid-template-columns: repeat(4, 1fr);).

Now I'm wondering if there's a way to do this more effectively with better readability, preferably with functional programming standards?

const numbers = [3, 2, 1, 6, 5, 4, 9, 8, 7]
const signs = ["AC", "√", "%", "÷", "*", "-", "+", "00", "0", ".", "="]

const alphanumeric = numbers.toString().split(",").concat(signs)

const fillButtons = () => {  
    const sortedArray: Array<string> = []
    let findSignIndex = 0
    let findNumberIndex = numbers.length - 1

    alphanumeric.forEach((_: string, index: number) => {
        if (index <= 3) {
            sortedArray.push(signs[findSignIndex++])
        }
        else if (index % 3 === 0 && findNumberIndex >= 0) {
            sortedArray.push(numbers[findNumberIndex--].toString())
            sortedArray.push(signs[findSignIndex++])
        }
        else if (findNumberIndex >= 0) {
            sortedArray.push(numbers[findNumberIndex--].toString())
        }
        else if (findSignIndex >= 0 && index < (alphanumeric.length - 3)) {
            sortedArray.push(signs[findSignIndex++])
        }
    });

    return sortedArray
}

This is the resulting array: ['AC', '√', '%', '÷', '7', '8', '9', '*', '4', '5', '6', '-', '1', '2', '3', '+', '00', '0', '.', '=']

This is the map:

{fillButtons().map((character: string, index: number) => (
    <button key={index} className="calculator__button">
        {character}
    </button>
))}

This is the result:

This is the result:



Solution 1:[1]

The problem

We want to assign "sign"s to corresponding "slots", but we need to find a declarative way to do it.

Actually there can not be a sensible "functional programming" solution, because the problem is not in the complexity of computation logic, but in the way that we want to store placement of buttons.

Solution 1

Use declarative power of grid template areas and forget about reordering arrays completely.

.controls {
  display: grid;
  grid-template-areas: 
    "AC sqrt percent div"
    "n7 n8 n9 mul"
    "n4 n5 n6 sub"
    "n1 n2 n3 sum"
    "doublezero n0 dot eq";
}

const numbers = [3, 2, 1, 6, 5, 4, 9, 8, 7];
const signs = ["AC", "?", "%", "÷", "*", "-", "+", "00", "0", ".", "="];

// but we are forced to store this clunky map, because
// ? % ÷ * + . = can not be used inside a grid area name
const signsToGridLabels = {
  "AC": 'AC',
  "?": 'sqrt',
  "%": 'percent',
  "÷": 'div',
  "*": 'mul',
  "-": 'sub',
  "+": 'sum',
  ".": 'dot',
  "=": 'eq',
  "00": 'doublezero',
};

const App = () => (
    <>
      <div className="display"></div>
      <div className="controls">
        {numbers.concat(signs).map((el) => {
          return (<div style={{ gridArea: signsToGridLabels[el] ?? `n${el}` }}>{el}</div>)
        })}
      </div>
    </>
  );

CodePen

(Not so much of a) Solution 2

Define a single "template" with grid-template-columns: repeat(4, 1fr);

const template = [
  'AC', '?', '%', '÷',
  '7', '8', '9', '*',
  '4', '5', '6', '-',
  '1', '2', '3', '+',
  '00', '0', '.', '='
];

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Temoncher