3

I have following three arrays, which defines the order of some texts

arr1 = ['ab', 'bc', 'ca', 'ac']
arr2 = ['lm', 'mn', 'ml']
arr3 = ['ij', 'kj', 'pr']

I want to sort array below based on the array above. Each string of myArray is consists of 5 characters where each 2 character are from the characters of the above 3 arrays. That is, arr1 has the highest priority, arr2 has priority over arr3 but less priority than arr1. arr3 has the lowest priority.

First 2 character of each string in myArray always match at least one string in arr1, middle two character match arr2 and last two character match arr3.

myArray = ['acmnkj', 'bcmlij', 'camnij', 'bcmnij',]

How can I sort myArray so that the results are sorted by arr1, arr2 and arr3. Expected sorted array ['bcmnij', 'bcmlij', 'camnij', 'acmnkj']

How can do this?

3 Answers 3

2

const arr1 = ['ab', 'bc', 'ca', 'ac']
const arr2 = ['lm', 'mn', 'ml']
const arr3 = ['ij', 'kj', 'pr']

const myArr = ['acmnkj', 'bcmlij', 'camnij', 'bcmnij']

const f = (s,a,i)=>a.indexOf(s.substring(2*i,2*i+2))

myArr.sort((x,y)=>[arr1,arr2,arr3].reduce((a,c,i)=>a || f(x,c,i)-f(y,c,i),0))

console.log(myArr)

Sign up to request clarification or add additional context in comments.

Comments

1

You could take an object with the order of the parts and compare sliced parts against.

const
    arr1 = ['ab', 'bc', 'ca', 'ac'],
    arr2 = ['lm', 'mn', 'ml'],
    arr3 = ['ij', 'kj', 'pr'],
    data = ['acmnkj', 'bcmlij', 'camnij', 'bcmnij'],
    order = Object.fromEntries([...arr1, ...arr2, ...arr3].map((v, i) => [v, i + 1]));

data.sort((a, b) => {
    let i = 0;
    while (i < 6) {
        const r = order[a.slice(i, i + 2)] - order[b.slice(i, i + 2)];
        if (r) return r;
        i += 2;
    }
    return 0;
});

console.log(data);

A slightly different approach with replacing the strings by an order value for comparing by string.

const
    getOrder = s => s.replace(/../g, k => order[k]),
    arr1 = ['ab', 'bc', 'ca', 'ac'],
    arr2 = ['lm', 'mn', 'ml'],
    arr3 = ['ij', 'kj', 'pr'],
    data = ['acmnkj', 'bcmlij', 'camnij', 'bcmnij'],
    order = Object.fromEntries([...arr1, ...arr2, ...arr3].map((v, i) => [v, (i + 1).toString().padStart(2)]));

data.sort((a, b) => getOrder(a).localeCompare(getOrder(b)));
console.log(order)
console.log(data);

Comments

1

You could create an object which maps the priority for each array

createOrder = (arr) => Object.fromEntries(arr.map((c,i) => [c,i]))

and then create an array of orders.

orders = [arr1,arr2,arr3].map(createOrder)

I'm assuming that there could be duplicate strings within the arrays. So, a flat order object is not created.

// orders array

[
  {
    "ab": 0,
    "bc": 1,
    "ca": 2,
    "ac": 3
  },
  {
    "lm": 0,
    "mn": 1,
    "ml": 2
  },
  {
    "ij": 0,
    "kj": 1,
    "pr": 2
  }
]

Then sort your array. Get the parts for each string

const partsA = a.match(/.{2}/g)

This can be changed based on your actual data. Here, it matches every 2 characters. If your input is 'ac-mn-kj', you'd be splitting at -.

Then loop until you find a difference in the order of each parts using some.

This works for any number of input arrays or format of the string in myArray

const arr1 = ['ab', 'bc', 'ca', 'ac'],
      arr2 = ['lm', 'mn', 'ml'],
      arr3 = ['ij', 'kj', 'pr'],
      createOrder = (arr) => Object.fromEntries(arr.map((c,i) => [c,i])),
      orders = [arr1,arr2,arr3].map(createOrder),
      myArray = ['acmnkj', 'bcmlij', 'camnij', 'bcmnij']

myArray.sort((a,b) => {
  const partsA = a.match(/.{2}/g) // can change based on your requirement
  const partsB = b.match(/.{2}/g)
  
  let returnValue;
  partsA.some((p, i) => returnValue = orders[i][p] - orders[i][partsB[i]])
  return returnValue
})

console.log(myArray)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.