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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.