74

I'm learning JavaScript using W3C and I didn't find an answer to this question.

I'm trying to make some manipulations on array elements which fulfill some condition.

Is there a way to do it other than running on the array elements in for loop? Maybe something like (in other languages):

foreach (object t in tArray)
   if (t follows some condition...) t++;

another thing, sometimes I want to use the element's value and sometimes I want to use it as a reference. what is the syntactical difference?

As well, I'll be happy for recommendations on more extensive sites to learn JavaScript from. thanks

1

10 Answers 10

73

In most browsers (not IE <= 8) arrays have a filter method, which doesn't do quite what you want but does create you an array of elements of the original array that satisfy a certain condition:

function isGreaterThanFive(x) {
     return x > 5;
}

[1, 10, 4, 6].filter(isGreaterThanFive); // Returns [10, 6]

Mozilla Developer Network has a lot of good JavaScript resources.

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

2 Comments

Just wanted to add that it has been added to IE from version 9 onwards.
Side note: if you want to manipulate the the result array you are effectivly looping twice. (Alt: linq delayed execution.)
37

Use ES6 Array.filter() and arrow functions with expression body:

myArray.filter(x => x > 5)

A bit more concise than @Beauty's answer.

Comments

13

Here a short way to write a filter. From an array of numbers it returns all values greater than 5.

myArray.filter((x) => { return x > 5; })

Usage example:

var filterResult = [1, 10, 4, 6].filter((x) => { return x > 5; });
console.log(filterResult); // returns [ 10, 6 ]

And here a filter for an array of objects, which checks a property condition.

myArray.filter((x) => { return x.myNumber > 5; })

Usage example:

var myArray = [{myNumber: 1, name: 'one'}, {myNumber: 3, name: 'tree'}, {myNumber: 6, name: 'six'}, {myNumber: 8, name: 'eight'}];
var result = myArray.filter((x) => { return x.myNumber > 5; });
console.log(result); // returns [ { myNumber: 6, name: 'six' }, { myNumber: 8, name: 'eight' } ]

Comments

9

You can use Array.prototype.find, wich does exactly what you want, returns the first element fullfilling the condition. Example:

> ([4, {a:7}, 7, {a:5, k:'r'}, 8]).find(o => o.a == 5)

{a:5, k:'r'}

Comments

4

You can use for ... in in JavaScript:

for (var key in array) {
    if (/* some condition */) {
        // ...
    }
}

As of JavaScript 1.6, you can use this, too:

for each (var element in array) {
    // ...
}

These are mainly meant to traverse object properties. You should consider to simply use your for-loop.

EDIT: You could use a JavaScript framework like jQuery to eliminate these cross-browser problems. Give it a try. Its $.each()-method does the job.

6 Comments

True, these methods work, but they are often recommended against. The reason is that it also enumerates other properties of the array object (and a lot of libraries add such properties) which will produce unpredictable results.
@sje397: Thats right. I highly recommend jQuery for this. Its $.each()-method works really nice and provides closures. Since JavaScript has function-scope, this can be really helpful when doing lots of stuff in your loops.
The actual set of properties enumerated by for...in is entirely predictable, although it does vary across browsers. What isn't generally predictable is the iteration order. For iterating over an array, for...in is generally a bad idea.
It would be quite useless loading a full library in order to iterate over an array :p
@Golmote: Most JavaScript applications could benefit from jQuery. I suppose that this are not the only lines of code that exist in this project.
|
2

About arrays

What you usually want for iterating over array is the forEach method:

arr.forEach(function(el) {
  alert(el);
});

In your specific case for incrementing each element of array, I'd recommend the map method:

arr = arr.map(function(t){ return t+1; });

There are also filter, reduce, and others, which too come in handy.

But like Tim Down already mentioned, these won't work by default in IE. But you can easily add these methods for IE too, like shown in MDC documentation, or actually you can even write simpler versions than the ones in MDC documentation (I don't know why they are so un-JavaScript-y over there):

if (!Array.prototype.forEach) {
  Array.prototype.forEach = function(func, scope) {
    for (var i = 0, len = this.length; i < len; i++) {
      func.call(scope, this[i], i, this);
    }
  };
}

But don't use the for ... in construct for arrays - this is meant for objects.

About references

Another thing, sometimes I want to use the element's value and sometimes I want to use it as a reference. What is the syntactical difference?

In JavaScript every variable is in fact a reference to some object. But those references are passed around by value. Let me explain...

You can pass an object to a function that modifies the object and the changes will be seen outside the function:

function incrementHeight(person) {
  person.height = person.height + 1;
}
var p = {height: 10);
alert(p.height); // outputs: 10
incrementHeight(p);
alert(p.height); // outputs: 11

Here you modify the value to which the person reference points to and so the change will be reflected outside the function.

But something like this fails:

function incrementHeight(height) {
  height = height + 1;
}
var h = 10;
alert(h); // outputs: 10
incrementHeight(h);
alert(h); // outputs: 10

Here you create a completely new object 11 and assign its reference to variable height. But variable h outside the function still contains the old reference and so remains to point at 10.

Comments

2

Write a generic function that accepts various conditions:

function array_only(arr, condition) {
    hold_test=[]
    arr.map(function(e, i) {if(eval(condition)){hold_test.push(e)}})
    return(hold_test)
    }

Example:

use_array = ['hello', 'go_there', 'now', 'go_here', 'hello.png', 'gogo.log', 'hoho.png']

Usage:

return only elements containing .log extension:

array_only(use_array, "e.includes('.log')")

[ 'gogo.log' ]

return only elements containing .png extension:

array_only(use_array, "e.includes('.png')")

[ 'hello.png', 'hoho.png' ]

return only elements NOT containing .png extension:

array_only(use_array, "!e.includes('.png')")

[ 'hello', 'go_there', 'now', 'go_here', 'gogo.log' ]

return elements containing set of extensions and prefixes:

array_only(use_array, "['go_', '.png', '.log'].some(el => e.includes(el))")

[ 'go_there', 'go_here', 'hello.png', 'gogo.log', 'hoho.png' ]

You can easily pass MULTIPLE CONDITIONS

return all png files that are less than 9 characters long:

array_only(use_array, "e.includes('.png') && e.length<9")

[ 'hoho.png' ]

Comments

2

I am joining in late, but I have an interesting solution. If you only want to filter a single element i.e the first element that satisfies the condition, you could use the JS find function.

myArray.find(x => x > 5)

Comments

0

Just came across the same problem. Tim Down came close, he just needed a wrapper to the length of the filtered array:

// count elements fulfilling a condition
Array.prototype.count = function (f) {
  return this.filter(f).length;  
};

Usage:

// get the answer weight from the question's values array
var w = Math.pow(q.values.count(function(v) { return v !== -1; }), -1);

I hope that answers this long standing question!

Comments

0

Problem:

I need to know if a client set exists for any PJ client.

Solution:

function deveExibirLista(lst: Clientes[]){
    return lst.some(cli => cli.Documento === 14);
}

It's return boolean

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.