12

I have an object and I want to iterate over some specific keys of that object. How to achieve this?

Consider the snippet below:

How can I iterate over table1,table2 and table3 keys and not all of them?

var table_object = {
  table1: "hello world",
  table1_name: "greetings_english.html",
  table2: "hola",
  table2_name: "greetings_spanish.html",
  table3: "Bonjour",
  table3_name: "greetings_french.html"
};

6
  • Instead of for (var key in table_object) just use for (var key of ["table1", …])? Commented Oct 25, 2017 at 12:34
  • It can be, but the keys will be dynamically created on an event's occurrence and named considering the number of files. Commented Oct 25, 2017 at 12:37
  • Then maybe you want to store the number of files, and use for (var i=1; i<=fileCount; i++) { var key = "table"+i; … } Commented Oct 25, 2017 at 12:40
  • Or maybe it would be much easier if you stored the tables and tablenames as two separate arrays. Commented Oct 25, 2017 at 12:41
  • Why did you tag this jquery if you want vanilla js? Commented Oct 25, 2017 at 13:04

7 Answers 7

16

You could filter the keys and then iterate the rest.

var table_object = { table1: "hello world", table1_name: "greetings_english.html", table2: "hola", table2_name: "greetings_spanish.html", table3: "Bonjour", table3_name: "greetings_french.html" };

Object
    .keys(table_object)
    .filter(function (k) { return !/_/.test(k); })
    .forEach(function (k) { console.log(table_object[k]); });

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

3 Comments

/^table(\d+)$/ will explicitly match table followed by some digits.
@NinaScholz not a prefix, it's wrapped in ^$.
/^([a-zA-Z0-9$]+)$/, or /^([a-zA-Z$]+)(\d+)$/. Or you can change the regex, or the whole filter function.
7

You have to specify which keys you have to iterate through:

var table_object = {
  table1: "hello world",
  table1_name: "greetings_english.html",
  table2: "hola",
  table2_name: "greetings_spanish.html",
  table3: "Bonjour",
  table3_name: "greetings_french.html"
};

var keysToIterateThrough = ["table1", "table2", "table3"];
keysToIterateThrough.forEach(key => {
    var value = table_object[key];
    console.log(`key: ${key} => value: ${value}`);
})

1 Comment

Is an option, but filtering by regex is also an option.
3

You have to use Object.keys in order to find out all the object keys then apply a filter method in order to filter them.

var table_object = {
  table1: "hello world",
  table1_name: "greetings_english.html",
  table2: "hola",
  table2_name: "greetings_spanish.html",
  table3: "Bonjour",
  table3_name: "greetings_french.html"
};
var keysToIterate = ["table1", "table2", "table3_name"];
let values=Object.keys(table_object)
                .filter(a=>keysToIterate.includes(a))
                .map(a=> table_object[a]);
console.log(values);

3 Comments

Wouldn't it be simpler (and probably more efficient) to do keysToIterate.filter(a => a in table_object) instead of Object.keys(table_object).filter(a => keysToIterate.includes(a))?
@IlmariKaronen, no, because keysToIterate is the array with keys we needed. He have to filter the keys of object.
@IlmariKaronen Yes, that would work. Whether it's more efficient depends on how large the object usually is and how often the keysToIterate are not part of the object.
2

Could try something like

var keys = ['table1', 'table2', 'table3']
Object.keys(table_object).forEach(function(key) {
    if (keys.indexOf(key) != -1) {
        var table_value = table_object[key]
    }
})

1 Comment

You can speed it up by iterating over keys.
1

It may not be possible to iterate over limited keys, but you can have an array of keys which you want to iterate. Then loop over that array to get the corresponding value from the object

var objKeys = ['table1', 'table2', 'table3']

var table_object = {
  table1: "hello world",
  table1_name: "greetings_english.html",
  table2: "hola",
  table2_name: "greetings_spanish.html",
  table3: "Bonjour",
  table3_name: "greetings_french.html"
};

objKeys.forEach(function(item) {
  console.log(table_object[item])

})

1 Comment

for ( var i = 0; i < objKeys.length; i ++ ) {} is supported in almost every browser and every version of that.
1

I think a better way to do it in this case is making your object like this:

var table = {
    "hello world": "greetings_english.html",
    "hola": "greetings_spanish.html",
    "bonjour": "greetings_french.html"
};

for( var i in table ) {
    console.log( i );
    console.log( table[ i ] );
}

Or you could create two arrays:

var greetings = [
    "hello world",
    "hola",
    "bonjour"
];
var names = [
    "greetings_english.html",
    "greetings_spanish.html",
    "greetings_french.html"
];

for( var i = 0; i < greetings.length; i ++ ) {
    console.log( greetings[ i ] );
    console.log( names[ i ] );
}

You can make a table using this method

But in any case of your question:

var table = {
    table1: "hello world",
    table1_name: "greetings_english.html",
    table2: "hola",
    table2_name: "greetings_spanish.html",
    table3: "bonjour",
    table3_name: "greetings_french.html"
};

// Now there are three methods

console.log( "--- Method 1 ---" );
Object.keys( table )
      .filter( function( key ) {
          return /^table(\d+)$/.test( key );
      } )
      .forEach( function( key ) {
          console.log( key );
          console.log( table[ key ] );
          console.log( table[ key + "_name" ] );
      } );
      
console.log( "--- Method 2 ---" );
for ( var i in table ) {
    if ( /^table(\d+)$/.test( i ) ) {
        console.log( i );
        console.log( table[ i ] );
        console.log( table[ i + "_name" ] );
    }
}
      
console.log( "--- Method 3 ---" );
var keys = [
    "table1",
    "table2",
    "table3"
];
for ( var i = 0; i < keys.length; i ++ ) {
    console.log( keys[ i ] );
    console.log( table[ keys[ i ] ] );
    console.log( table[ keys[ i ] + "_name" ] );
}

Method 2 would be the best.

Comments

1

You don't need fancy filters or regular expression to accomplish such a simple task! Ignore those misleading answers and start using the full power of JavaScript!
You should use the Object.defineProperty() method on your object and set to enumerable: false all the properties you don't want to iterate through. In this way you also decouple your naming convention from your logic. Let me show you:

// Defining iterable properties. This ones will be returned
// by Object.keys()

var table_object = {
  table1: "hello world",
  table2: "hola",
  table3: "Bonjour",
  // It works even if you declare them in advance
  // table1_name: "greetings_english.html",
  // table2_name: "greetings_spanish.html",
  // table3_name: "greetings_french.html",
};

// Declaring the not iterable properties. They can still be
// accessed, but they will not be iterated through

Object.defineProperty(table_object, "table1_name", {
  // delete the next line if you have already declared it
  value: "greetings_english.html", 
  enumerable: false
});

Object.defineProperty(table_object, "table2_name", {
  // delete the next line if you have already declared it
  value: "greetings_spanish.html",
  enumerable: false
});

Object.defineProperty(table_object, "table3_name", {
  // delete the next line if you have already declared it
  value: "greetings_french.html",
  enumerable: false
});

// Iterating through the object using for ... in, which iterates
// over the keys

for (var key in table_object) {
  console.log(table_object[key]);
}

The not enumerable properties can still be retrieved along with all the enumerable ones using Object.getOwnPropertyNames().
However, if you are planning to actually use this second method to iterate through all the properties when filtering is not needed anymore I've to give you some advice:

  • enumerable can be set back to true, so if it a one-time change I'd highly suggest to revert it.

  • If filtering is toogled back and forth more often than not, then you should check twice the structure of your object, since there may be more suitable options for your needs (such as arrays into the object).

2 Comments

I thought about that but it's much slower than filtering the keys.
Also, if you really care about performance, why not using loops over filter function?. I'm not saying this is the fastest solution, of course, but I think that's the most semantically correct one and, most important thing, it's not that slow to freeze your browser ;P

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.