7

I have an array with sizes like this:

var arr = [
  'small',
  'small',
  'small',
  'small',
  ...
  'medium',
  'medium',
  'medium',
  'medium',
  ...
  'big',
  'big',
  ...
];

I need to reorganize this array according to this order:

var order = ['small', 'small', 'medium', 'medium', 'big'];

So the result ends up being something like this:

var arr = [
  'small',
  'small',
  'medium',
  'medium',
  'big',

  'small',
  'small',
  'medium',
  'medium',
  'big'

  ...
];

I'm aware of other similar questions in SO but I couldn't find anything so far. I'm unsure how to approach this. I was thinking sort should do but what do I test for? It seems simple but I'm stuck, don't know where to begin. Any hints?

5
  • I think you need to show an actual example of the array before and after. Right now I cannot see what makes the array split on the two sets you are showing in the output Commented Mar 21, 2013 at 5:46
  • Title: Sorting array with another array Wait what? Commented Mar 21, 2013 at 6:31
  • @Derek: Feel free to edit, don't know how to define this problem better... Commented Mar 21, 2013 at 6:36
  • 1
    @Derek: Ah, that makes sense. Too tired to even think semantics... Commented Mar 21, 2013 at 6:39
  • @elclanrs - Can you just count how many "small" and "medium" you have there and divide it out? Commented Mar 21, 2013 at 6:50

6 Answers 6

7

Just define a scorer for your sort method. Here is your code. Try it

var init_arr = ['small', 'big', 'big', 'medium'];

var scorer = {
   small: 0,
   medium: 1,
   big: 2
}

// You can use the same array too. I am creating new one.
var final_arr = init_arr.sort(function(a,b) {
   return scorer[a]-scorer[b];
});

alert(final_arr); //small, medium, big, big

Working Fiddle

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

6 Comments

Very nice, better than mine +1.
@gdoron Glad you liked it :)
I'm afraid this isn't the desired result. See the example.
I hope this is what OP needs, judging from his output example, I think we are missing some info
@JanDvorak Yep..My bad!! I misinterpreted :(. Still I am leaving the answer in case it helps somebody else.
|
1

This answer works only for the exact case you have described, i.e. where the length of the array is an even multiple of 5 and the values are sorted into small, medium and big and there are twice as many of each small and medium as big.

It may work for any sorted array of values where length % 5 == 0, but the results might not be want you want:

function reOrder(array) {
  var result = [];
  var f = array.length/5; // this must be an integer
  var t;

  for (var i=0; i<f; i++) {
    t = i*2;
    result.push.call(result, array.slice(t, t+2));
    t = f*2 + i*2;
    result.push.call(result, array.slice(t, t+2));
    t = f*4 + i;
    result.push.call(result, array.slice(t, t+1));
  }
  return result; 
} 

var a = ['s','s','s','s','s','s','m','m','m','m','m','m','b','b','b'];
alert(reOrder(a)); // s,s,m,m,b,s,s,m,m,b,s,s,m,m,b

1 Comment

+1 This seems to work for the case I described, but it's fairly random so it might not work for long term solution.
1

Well, I finally ended up with this solution that works:

function orderBy(arr, order) {
  var result = [],
      i = 0, len = arr.length,
      index;

  while (result.length < len) {
    index = arr.indexOf(order[i]);
    result.push(arr[index]);
    arr.splice(index, 1);
    i = i >= order.length-1 ? 0 : ++i;
  }

  return result;
}

It modifies the original array but that's ok.

Demo: http://jsbin.com/umizat/1/edit

4 Comments

I would love to know the real world application of this
@mplungjan: I have a Masonry grid with 3 different sized boxes. To make a complete grid (no holes or weird whitespace), the boxes must follow a given pattern (small, small, medium, medium, big). That's the general idea. I ended up just filling the holes with a "disabled" looking box instead of going through all this trouble.
@elclanrs well damn, if I had seen this before I wouldn't have spent the time making my fiddle and function >< lol (you should accept the answer so others like me that find the problem interesting and create something to work without checking all the answers first :P)
Though, to my credit, if the input array on this doesn't match exactly with the order it gives 'undefined' back rather than adding the extra elements at the end. But I somehow doubt you'd have have an array that doesn't fit the order exactly. lol
0

why dont you create 3 arrays and split your data according to sizes, then you can retrieve data in a given order.

like;

SMALL[];
MEDIUM[];
BIG[];

for(i,j,k : upto array lengths : i++,j++,k++){

   nwArray.add(SMALL[i]);
   nwArray.add(SMALL[++i]);
   nwArray.add(MEDIUM[j]);
   nwArray.add(MEDIUM[++j]);
   nwArray.add(BIG[k]);

}

return newArray;

Comments

0

My approach would be looping over the order array and pulling out element till the array is empty or doesn't have the required element.

var sorted = [];
var arr = [
  'small',
  'small',
  'small',
  'small',
  ...
  'medium',
  'medium',
  'medium',
  'medium',
  ...
  'big',
  'big',
  ...
];
var order = ['small', 'small', 'medium', 'medium', 'big'];

out:
while (true) {
  for (var i = 0; i < order.length; i++) {
    var index = arr.indexOf(order[i]);
    if ((index === -1) or (arr.length === 0)) {
      break out;
    } else {
      var elem = arr.splice(index, 1);
      sorted.append(elem[0]);
    }
}

Comments

0

I know this question is old, and you have an answer you are currently using, but I wanted to offer up this example and JSFiddle for a solution that would work with any type of modification you might make to end.

Note anything left over in the original array gets added to the end of the new array, and is not excluded. If there aren't enough items in the array to fill the requirements of order, the missing elements are skipped from the order.

Now, to the function:

function mySort(arr, order) {
    var newAr = [];
    var orIndex = 0;
    while(arr.length != 0) {
        var type = order[orIndex];
        var ind = arr.indexOf(type);
        if(ind != -1) {
            newAr.push(type);
            arr.splice(ind, 1);
        }
        orIndex++;
        if(orIndex >= order.length) {
            orIndex = 0;
        }
    }
    return newAr;
}

What this does, is it takes your example arrays of:

var arrTest = [
  'small',
  'small',
  'small',
  'small',
  'small',
  'small',
  'small',
  'small',
  'medium',
  'medium',
  'medium',
  'medium',
  'medium',
  'medium',
  'medium',
  'medium',
  'big',
  'big',
  'big',
  'big',
];
var orderTest = ['small', 'small', 'medium', 'medium', 'big'];

Now, you can change these all you want, but it does a text search of them, so if you want it sorted, make sure it is the same in both the full array and the order array. Now, to use the function, you would do:

var sortedArray = mySort(arrTest, orderTest);

Or, for how I demonstrate in the Fiddle:

alert(mySort(arrTest, orderTest).join('\n'));

And that should work for any situation that involves the two and the order can easily be modified.

Hope that helps!

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.