Dmytro Kozlov
Dmytro Kozlov

Reputation: 175

Multiple sorting in JavaScript

I have an array like ['1','0', '3', 'a', 'b', 'z', 'xs', 'l', 'm', 'xl'] and a pattern array like ['m', 'l', 'xs', 'xl'].

I need sort entered array first by pattern and other part of entered array by asc pattern.

The output I have to get is ['m', 'l', 'xs', 'xl', '0', '1', '3', 'a', 'b', 'z'];

I'm implemented something like this

function sort(a, b) {

  var mappattern = {'m': 1, 'l': 2, 'xs': 3, 'xl': 4}

  if (mappattern[a.name] && mappattern[b.name]) {
    return mappattern[a.name] - mappattern[b.name];
  }

  return -1
}

But this works incorrect

Upvotes: 1

Views: 89

Answers (4)

mrgrechkinn
mrgrechkinn

Reputation: 908

You can sort by this way, using array index

var array = ['1','0', '3', 'a', 'b', 'z', 'xs', 'l', 'm', 'xl'];
array.sort(function (a, b) {
    var pattern = ['m', 'l', 'xs', 'xl'];
    var aIn = pattern.indexOf(a);
    var bIn = pattern.indexOf(b);
    if (aIn == bIn) {
        return a.localeCompare(b);
    }
    if (aIn <= -1) {
        return 1;
    } else if (bIn <= -1) {
        return -1;
    } else {
        return aIn - bIn;
    }
});
document.write(JSON.stringify(array));

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386680

You could take a shorter approach by using values for sorting the pattern to top and a default value of zero which takes the other parts of conditions.

const
    order = { m: -4, l: -3, xs: -2, xl: -1, default: 0 },
    sort = (a, b) =>
        (order[a] || order.default) - (order[b] || order.default) ||
        a > b || -(a < b);

var array = ['1', '0', '3', 'a', 'b', 'z', 'xs', 'l', 'm', 'xl']

array.sort(sort);
console.log(...array);

Upvotes: 2

Sifat Haque
Sifat Haque

Reputation: 6067

At first i've separated the pattern items and others alphanumeric items from the input array. Then applied the normal sorted method. Here is the solution

const input = ["1", "0", "3", "a", "b", "z", "xs", "l", "m", "xl"];
const defaultPattern = ["m", "l", "xs", "xl"];
console.log(customSort(input, defaultPattern));

function customSort(inputArray = [], defaultPattern = []) {
  // separating pattern and other array items
  const inputObj = inputArray.reduce((acc, item) => {
    if (defaultPattern.includes(item)) {
      acc["pattern"] ? acc["pattern"].push(item) : (acc["pattern"] = [item]);
    } else {
      acc["others"] ? acc["others"].push(item) : (acc["others"] = [item]);
    }
    return acc;
  }, {});

  // Sorting
  const inputPatterns = inputObj["pattern"];
  inputPatterns.sort((a, b) => {
    return defaultPattern.indexOf(a) - defaultPattern.indexOf(b);
  });
  const others = inputObj["others"].sort();
  return [...inputPatterns, ...others];
}

Upvotes: 0

Buszmen
Buszmen

Reputation: 2426

To fix your approach, first - I don't know why you get name property out of a string. Then, you have to sort elements within pattern (that part is now working), sort elements outside of pattern and sort between elements from each of those groups.

Here's a draft solution:

const mappattern = {
  'm': 1,
  'l': 2,
  'xs': 3,
  'xl': 4
};

function sort(a, b) {
  if (mappattern[a] && mappattern[b]) {
    return (mappattern[a] - mappattern[b]);
  }

  if (mappattern[a] && !mappattern[b]) {
    return -1;
  }

  return a.localeCompare(b);
}

const res = ['1', '0', '3', 'a', 'b', 'z', 'xs', 'l', 'm', 'xl'].sort(sort);

document.write(JSON.stringify(res))

Upvotes: 0

Related Questions