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?*

Community
  • 1
  • 1
IntricatePixels
  • 1,219
  • 6
  • 29
  • 55
  • 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? – Bergi Mar 24 '16 at 01: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. – Bergi Mar 24 '16 at 02:03

4 Answers4

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'; })
Brett DeWoody
  • 59,771
  • 29
  • 135
  • 184
  • Elegant naming the function 'tee'. +1 – Hrishi Mar 28 '16 at 04:32
  • 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? – IntricatePixels May 06 '16 at 16:59
  • Have added non-ES6 version, perhaps that would work. –  May 06 '16 at 17:48
  • ES5 version worked on all browsers, including Safari, thanks! – IntricatePixels May 24 '16 at 21:22
  • Just asking, Can we do this in PHP ?? – Rahul_Dange Mar 27 '20 at 05:13
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
choz
  • 17,242
  • 4
  • 53
  • 73
  • Thank you, that did it! I was trying it the long and hard way. – IntricatePixels Mar 24 '16 at 01:16
  • @IntricatePixels Glad it helped. – choz Mar 24 '16 at 01:36
  • No, you [absolutely cannot use that comparison function](http://stackoverflow.com/q/24080785/1048572) to accomplish this. – Bergi Mar 24 '16 at 01:59
  • @Bergi Can you provide a sample where it could go wrong with string comparison like this? Ill investigate this once im back on pc.. – choz Mar 24 '16 at 02:11
  • Check the counterexamples section in the linked answer. In your case, calling he comparison function with the `Sarah` object in the first argument would need to yield `-1`, which you don't; this will certainly trip up the sorting algorithm. – Bergi Mar 24 '16 at 02:15
  • @Bergi I have updated my answer as your comparison function suggestion. But, I found that your answer in that link pretty surprising. I am not sure since it looks like every browsers have their [array sort algorithm](http://stackoverflow.com/questions/234683/javascript-array-sort-implementation) different. And based on your thesis there, I could not replicate your `quick counterexample` (I left on comments). And I kept trying on my sample array to reproduce that sort issue which up til now I am still unable to. Or are you just referring to Opera browser in your post? – choz Mar 24 '16 at 06:57
  • @choz it's really simple.The sort function needs to return -1, 0, or 1. That's it. That's the spec. Otherwise, the behavior is unpredictable. It might work on some datasets, and not others, and in some browsers, or not others. I'm also puzzled why you would leave in the broken, incorrect `return second.Name == "Sarah"` as a comment. –  Mar 24 '16 at 19:44
  • @IntricatePixels Please unaccept this broken answer. Among other problems, it will re-order parts of your array that you did not necessarily want to be re-ordered. –  Mar 24 '16 at 20:09
  • 1
    @torazaburo That's just for Opera 12. – choz Mar 25 '16 at 01:34
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);
Nikhil Mahirrao
  • 3,547
  • 1
  • 25
  • 20
-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)
});
joemillervi
  • 1,009
  • 1
  • 8
  • 18