1

What I"m trying to accomplish is similar to the PHP solution from this other post on Stackoverflow, but with JavaScript:

Multidimensional array, find item and move to the top?

I'm returning an object with the following:

 $.get(uri, function (data) {

    self.options = [];

    $.each(data, function (index, item) {
        self.options.push(item);
    });
 });

self.options[] looks something like:

   Object 1: 
          Id: "1"
          Name: "Bill"
   Object 2: 
          Id: "2"
          Name: "Sarah"
   Object 3: 
          Id: "3"
          Name: "Mike"

I need to find "Sarah" in the array object and move it up to be the first item of the array. How can I accomplish this?*

2
  • The solution actually will look quite the same - only in JavaScript: a loop, a condition, a splice and an unshift statement. Now what is your problem, what have you tried, and how did it not work? Commented Mar 24, 2016 at 1:06
  • @IntricatePixels: If you have tried to code it yourself, you should show us that attempt by posting the not-yet-working code in your question so that we can help you with the problem(s) you're facing in doing this. Only asking for a solution without showing much effort is considered bad etiquette on SO. Commented Mar 24, 2016 at 2:03

4 Answers 4

14

You can literally write out the English description of your problem in JavaScript.

array.unshift(                      // add to the front of the array
  array.splice(                     // the result of deleting items
    array.findIndex(                // starting with the index where
      elt => elt.Name === 'Sarah'), // the name is Sarah
  1)[0]                             // and continuing for one item
)

Or, more compactly:

array.unshift(array.splice(array.findIndex(elt => elt.Name === 'Sarah'), 1)[0])

findIndex is not supported in Internet Explorer at all so to support IE 11 you can use a combination of map (Since IE 9) and indexOf (Since IE 8) - This gives you full, non-ever green, cross browser compatibility.

array.unshift(                      
  array.splice(                     
    array.map(function(e){ return e.Name}).indexOf('Sarah'), 
  1)[0]                             
)

But that doesn't handle the case where Sarah is missing, or there is more than one Sarah. A more general solution would be to split the incoming array into two, based on some condition, then recombine them. That's what this tee function does:

function tee(a, fn) {
  var non_matches = [];
  var matches = a.filter(function(e, i, a) {
    var match = fn(e, i, a);
    if (!match) non_matches.push(e);
    return match;
  });
  return matches.concat(non_matches);
}

Now, in ES6, you can obtain your result with

tee(a, e => e.Name === 'Sarah')

Or for older browsers, with ES5:

tee(a, function(e) { return e.Name === 'Sarah'; })
Sign up to request clarification or add additional context in comments.

5 Comments

Elegant naming the function 'tee'. +1
You were right, the solutin from @choz that I had marked as the correct answer does not seem to work in Safari or other browsers now (works in Chrome). I have unmarked it as the correct answer. However, I can't get the solution you provided to work either as I get a parse error: Unexpected token: operator (>). It looks like it does not like the "=>" part. Any thoughts?
Have added non-ES6 version, perhaps that would work.
ES5 version worked on all browsers, including Safari, thanks!
Just asking, Can we do this in PHP ??
4

You can use Array.prototype.sort to accomplish this.

E.g.

var arr = [];
arr.push({Id:"1", Name:"Bill"});
arr.push({Id:"2", Name:"Sarah"});
arr.push({Id:"3", Name:"Mike"});

arr.sort(function(first, second) {
  if (second.Name == "Sarah") return 1;
});

console.log(arr);
// [Object { Id="2",  Name="Sarah"}, Object { Id="1",  Name="Bill"}, Object { Id="3",  Name="Mike"}]

Or another alternative one,

var arr = [];
arr.push({Id:"1", Name:"Bill"});
arr.push({Id:"3", Name:"Mike"});
arr.push({Id:"2", Name:"Sarah"});

function getIndexByName(name) {
    for(var i = 0; i < arr.length; i++) {
        if (arr[i].Name == name) {
            return i;
        }
    }
}

var pos = getIndexByName("Sarah");
arr.splice(0, 0, arr[pos++]) // Insert Sarah at `arr` first position
arr.splice(pos, 1); // Remove old Sarah

9 Comments

Thank you, that did it! I was trying it the long and hard way.
@IntricatePixels Glad it helped.
@Bergi Can you provide a sample where it could go wrong with string comparison like this? Ill investigate this once im back on pc..
@torazaburo That's just for Opera 12.
|
1

You can use the sort method of array

var array = ['apple','zebra','cherry','grap'];

// 'zebra' at first index of array
array.sort( (first, second) => {
  if(first === 'zebra') return -1;
});
console.log('first', array);

// 'zebra' at last index of array
array.sort( (first, second) => {
  if(second === 'zebra') return -1;
});
console.log('last', array);

Comments

-1

Here is one way to do what you are asking.

$.get(uri, function (data) {

   self.options = [];
   var chosenName = 'Sarah'
   var tmp = [];
   $.each(data, function (index, item) {
       // if we find it while iterating through do not add it, store it it tmp
       if (item.Name === chosenName) {
          tmp.push(item);
       } else {
          self.options.push(item);
       }
   });
   // if we found it push it to the front of the array
   if (tmp.length > 0) self.options = tmp.concat(self.options)
});

2 Comments

If there are multiple matches - you will lose some data.
@zerkms good point I have adjusted my answer. The accepted answer is the way to go though unless you have a huge dataset.

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.