Jessica David
Jessica David

Reputation: 127

Custom Intl.Collator in JS

I need to sort this array

['$', 'z', 7, 'a', 1, '%', '.', 5, '% hello', ' ', 'f', '^' , '-', '_']

as

[ , %, % hello, _, -, ., ^, $, 1, 5, 7, a, f, z] 

But the result I'm getting is

[ , _, -, ., %, % hello, ^, $, 1, 5, 7, a, f, z] 

Is there any way to create custom collator? In this case, is it possible to get the position of any specific character or symbol say '%' before other symbols?

 var collator = Intl.Collator();
var letters = ['$', 'z', 7, 'a', 1, '%', '.', 5, '% hello', ' ', 'f', '^' , '-', '_'];
console.log(letters.sort(collator.compare));

Upvotes: 2

Views: 719

Answers (3)

arizafar
arizafar

Reputation: 3122

You can keep an array of order you want and then sort as following

let Order = { ' ': 1, '%': 2, '_': 4, '-': 5, '.': 6, '^': 7, '$': 8 }

let array = ['$', 'z', 7, 'a', 1, '%', '.', 5, '% hello', ' ', 'f', '^', '-', '_'];

array.sort((a, b) => {
	if (Order[a] && Order[b]) {
		return Order[a] - Order[b];
	} else {
		let x = [...a.toString()].find(e => Order[e]);
		let y = [...b.toString()].find(e => Order[e]);
		if (Order[x] && Order[y])
			return (Order[x]) - (Order[y]);
		return a.toString().localeCompare(b)
	}
});
console.log(array)

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386680

You could take a custom sorting by specifying letters to be sorted first.

This approach takes a sorting with map where each items is mapped to the following array and then all items are mapped by the order of the sorted indices.

[
    {
        index: 5,
        value: "%￿￿￿"
    },
    {
        index: 8,
        value: "%￿￿￿￿￿ ￿￿￿￿h￿￿￿e￿￿￿l￿￿￿l￿￿￿o"
    },
    {
        index: 0,
        value: "￿$￿￿"
    },
    {
        index: 9,
        value: "￿￿ ￿"
    },
    {
        index: 13,
        value: "￿￿￿_"
    },
    {
        index: 12,
        value: "￿￿￿-"
    },
    {
        index: 6,
        value: "￿￿￿."
    },
    {
        index: 11,
        value: "￿￿￿^"
    },
    {
        index: 4,
        value: "￿￿￿1"
    },
    {
        index: 7,
        value: "￿￿￿5"
    },
    {
        index: 2,
        value: "￿￿￿7"
    },
    {
        index: 3,
        value: "￿￿￿a"
    },
    {
        index: 10,
        value: "￿￿￿f"
    },
    {
        index: 1,
        value: "￿￿￿z"
    }
]

var array = ['$', 'z', 7, 'a', 1, '%', '.', 5, '% hello', ' ', 'f', '^', '-', '_'],
    first = '%$ ', // take % first, then $ then space then rest by standard sorting
    check = [...first, ''],
    result = array
        .map((item, index) => {
            var value = '';
            for (let c of [...item.toString()]) {
                value += check
                    .map(v => !check.includes(c) && !v || v === c ? c : '\uFFFF')
                    .join('');
            }
            return { index, value };
        })
        .sort((a, b) => a.value.localeCompare(b.value))
        .map(({ index }) => array[index]);

console.log(result);

Upvotes: 1

Ahmed Kesha
Ahmed Kesha

Reputation: 830

Could you try this I am not sure If that is completed solution for your issue or not

var collator = Intl.Collator();
        var letters = ['$', 'z', 7, 'a', 1, '%', '.', 5, '% hello', ' ', 'f', '^', '-', '_'];
        arr = letters.sort(collator.compare);
        arr.forEach((item, index) => {
            if (String(item).indexOf('%') >= 0) {
                arr.splice(0, index + 1, ...arr.slice(0, index + 1).sort())
            }
        });
        console.log(arr);

Upvotes: 1

Related Questions