Search code examples
javascriptarraysperformancesortingcomparison

How to sort an array by item type where strings should appear 1st then floats and integers while keeping same type precedence and no extra arrays used


Input:

[7,"a","b",5, 0.1, "c", 0.5, 9, 1, "e", "m", 0.3, 8.5, 74, 89,"f","r",0.5 ,"x", "y", 4, 7]

Output:

["a", "b", "c", "e", "m", "f", "r", "x", "y", 0.1, 0.5, 0.3, 8.5, 0.5, 7, 5, 9, 1, 74, 89, 4, 7]

function sorter(arr) {
    var arr1, arr2, arr3;
    arr1 = [];
    arr2 = [];
    arr3 = [];
    for (var i = 0; i < arr.length; i++) {
        if (typeof arr[i] === "string") {
            arr1.push(arr[i]);
        } else if (typeof arr[i] === 'number' && !isNaN(arr[i])) {
            if (Number.isInteger(arr[i])) {
                arr3.push(arr[i]);
            } else {
                arr2.push(arr[i]);
            }
        }
    }
    return [...arr1, ...arr2, ...arr3];
}


Solution

  • An approach based on a single sort comparator callback ...

    function orderByItemTypeOnly(a, b) {
      const precedences = {
        'string': 1,
        'float': 2,
        'int': 3,
      };
      const getType = val =>
        ((typeof val === 'number') && Number.isFinite(val))
          ? Number.isInteger(val) && 'int' || 'float'
          : (typeof val);
    
      const aType = getType(a);
      const bType = getType(b);
    
      return (
        (precedences[aType] || 4) - (precedences[bType] || 4)
      );
    }
    
    console.log([
    
      7, "a", "b", 5, 0.1, "c", 0.5, 9, 1, "e", "m",
      0.3, 8.5, 74, 89, "f", "r", 0.5, "x", "y", 4, 7
    
    ].sort(orderByItemTypeOnly));
    .as-console-wrapper { min-height: 100%!important; top: 0; }

    There is also the possibility of solving this task not by sort but based on a reduce approach ...

    function collectAndShiftItemByType(list, item, idx, arr) {
      if (list.length === 0) {
        list.push([], [], [], []);
      }
      const typeListIndex = ((typeof item === 'number') && Number.isFinite(item))
        ? (Number.isInteger(item) && 2 || 1)
        : (typeof item === 'string') ? 0 : 3;
    
      // push into sub lists ... [0]string, [1]float, [2]integer, [3]unknown.
      list[typeListIndex].push(item);
    
      if (idx >= arr.length - 1) {
        list = list[0]
          .concat(list[1])
          .concat(list[2])
          .concat(list[3]);
      }
      return list;
    }
    
    console.log([
    
      7, "a", "b", 5, 0.1, "c", 0.5, 9, 1, "e", "m",
      0.3, 8.5, 74, 89, "f", "r", 0.5, "x", "y", 4, 7
    
    ].reduce(collectAndShiftItemByType, []));
    .as-console-wrapper { min-height: 100%!important; top: 0; }