2

I wrote a simple function to access some values in the array below, and nested in the array are multiple objects.

My question has to do with my 2 loops. I understand that I must initially loop through the array to gain access to the 3 objects, but why must I loop through the 3 objects before I can access the values?

Basically why can't I run an initial for loop and access a sound by doing this:

animalNoises[i][animal][country]

the above returns as undefined for me. Does it have something to do with the way each 3 animal objects are structured?

Thanks for the help. I really appreciate the stack overflow community for the constant help.

function petSounds(animal, country) {
let phrase = ''
for (let i = 0; i < animalNoises.length; i++) {
 for (let key in animalNoises[i]){
 if (animal === key){
 let sound = animalNoises[i][key][country];
 phrase = animal + 's' + ' in ' + country + ' say ' + sound
 }
 }
 }
 return phrase
}
 let animalNoises = [
 { 'dog': {
 'America' : 'Woof! Woof!',
 'Germany' : 'Wau Wau!',
 'England' : 'Bow wow!',
 'Uruguay' : 'Jua jua!',
 'Afrikaans' : 'Blaf!',
 'Korea' : 'Mong mong!',
 'Iceland' : 'Voff voff!',
 'Albania' : 'Ham!',
 'Algeria' : 'Ouaf ouaf!'
 }
 },
 { 'cat': {
 'America' : 'Meow',
 'Germany' : 'Miauw!',
 'England' : 'mew mew',
 'Uruguay' : 'Miau Miau!',
 'Afrikaans' : 'Purr',
 'Korea' : 'Nyaong!',
 'Iceland' : 'Kurnau!',
 'Albania' : 'Miau',
 'Algeria' : 'Miaou!'
 }
 },
 { 'chicken': {
 'America' : 'Cluck cluck',
 'Germany' : 'tock tock tock',
 'England' : 'Cluck Cluck',
 'Uruguay' : 'gut gut gdak',
 'Afrikaans' : 'kukeleku',
 'Korea' : 'ko-ko-ko',
 'Iceland' : 'Chuck-chuck!',
 'Albania' : 'Kotkot',
 'Algeria' : 'Cotcotcodet'
 }
 }
];
Adriano
3,9945 gold badges36 silver badges58 bronze badges
asked Nov 21, 2018 at 5:10
4
  • 1
    Works with console.log(petSounds('dog', 'America')); -> dogs in America say Woof! Woof! and console.log(petSounds('chicken', 'Algeria')); -> chickens in Algeria say Cotcotcodet Commented Nov 21, 2018 at 5:11
  • the code seems alright. May be you are calling it with arguments which are not part of object's keys and hence it returns undefined. Commented Nov 21, 2018 at 5:17
  • Also, you do understand that this way you will get a single return value at the end of all the loops. Commented Nov 21, 2018 at 5:18
  • 4
    If you change the structure to a more reasonable {'dog': {...}, 'cat': {...}, 'chicken': {...}}, you will be able to do animalSounds[animal][country], with zero loops. Commented Nov 21, 2018 at 5:19

3 Answers 3

4

You need to update your json to simplify function (use an object keyed by animal type):

function petSounds(animal, country) {
 const sound = animalNoises[animal][country];
 const phrase = animal + 's' + ' in ' + country + ' say ' + sound;
 return phrase;
}
let animalNoises = {
 'dog': {
 'America': 'Woof! Woof!',
 'Germany': 'Wau Wau!',
 'England': 'Bow wow!',
 'Uruguay': 'Jua jua!',
 'Afrikaans': 'Blaf!',
 'Korea': 'Mong mong!',
 'Iceland': 'Voff voff!',
 'Albania': 'Ham!',
 'Algeria': 'Ouaf ouaf!'
 },
 'cat': {
 'America': 'Meow',
 'Germany': 'Miauw!',
 'England': 'mew mew',
 'Uruguay': 'Miau Miau!',
 'Afrikaans': 'Purr',
 'Korea': 'Nyaong!',
 'Iceland': 'Kurnau!',
 'Albania': 'Miau',
 'Algeria': 'Miaou!'
 },
 'chicken': {
 'America': 'Cluck cluck',
 'Germany': 'tock tock tock',
 'England': 'Cluck Cluck',
 'Uruguay': 'gut gut gdak',
 'Afrikaans': 'kukeleku',
 'Korea': 'ko-ko-ko',
 'Iceland': 'Chuck-chuck!',
 'Albania': 'Kotkot',
 'Algeria': 'Cotcotcodet'
 }
};
console.log(petSounds('cat', 'America'));
console.log(petSounds('dog', 'Iceland'));
console.log(petSounds('chicken', 'Germany'));

slider
13.1k1 gold badge29 silver badges45 bronze badges
answered Nov 21, 2018 at 5:29
Sign up to request clarification or add additional context in comments.

Comments

1

Your solution works, with single for loop. You missed specifying single quotes. When I simply console this it returns specific value.

animalNoises[0]['dog']['Korea']
"Mong mong!"

In loop you need to access from your array by specifying key name and country values.

It doesn't have anything to do with the way each 3 animal objects are structured

When I call your function it is running fine.

petSounds('dog', 'Korea')
"dogs in Korea say Mong mong!"

Or you can modify your function as below which does same reducing inner loop:

function petSounds(animal, country) {
let phrase = ''
 for (let i = 0; i < animalNoises.length; i++) {
 let key = Object.keys(animalNoises[i])[0];
 if (animal === key){
 let sound = animalNoises[i][key][country];
 phrase = animal + 's' + ' in ' + country + ' say ' + sound
 }
 }
 return phrase
}
answered Nov 21, 2018 at 6:55

4 Comments

I thought his second for loop was checking for the validity of the animal? It's so that it can make sure the key exists before trying to concatenate it to his return value
The second loop is not required. you can take key name by Object.keys(animalNoises[i])[0] to compare with animal
I think you're missing what I'm saying. Others have already suggested possibly changing the format of the JSON, but what if the JSON is provided from an outside source and your objects have extra keys? Plus what if there is a prototype property equal to the key you sent in? His second loop is checking to make sure that the object has it's own property of the animal.
In that case the second loop is required. But I think what he is asking in his question is : Why must I loop through the 3 objects before I can access the values? So as per his question he can access the values without looping. But if objects have extra keys then I agree to your comment.
1

If you want to keep the form you have now you can always use an Array#find(), and then a in operator check, and then with template literals you can easily create your string.

function petSounds(animal, country) {
 const noise = animalNoises.find(obj => animal in obj)[animal][country];
 return `${animal}s in ${country} say ${noise}`
}
 let animalNoises = [
 { 'dog': {
 'America' : 'Woof! Woof!',
 'Germany' : 'Wau Wau!',
 'England' : 'Bow wow!',
 'Uruguay' : 'Jua jua!',
 'Afrikaans' : 'Blaf!',
 'Korea' : 'Mong mong!',
 'Iceland' : 'Voff voff!',
 'Albania' : 'Ham!',
 'Algeria' : 'Ouaf ouaf!'
 }
 },
 { 'cat': {
 'America' : 'Meow',
 'Germany' : 'Miauw!',
 'England' : 'mew mew',
 'Uruguay' : 'Miau Miau!',
 'Afrikaans' : 'Purr',
 'Korea' : 'Nyaong!',
 'Iceland' : 'Kurnau!',
 'Albania' : 'Miau',
 'Algeria' : 'Miaou!'
 }
 },
 { 'chicken': {
 'America' : 'Cluck cluck',
 'Germany' : 'tock tock tock',
 'England' : 'Cluck Cluck',
 'Uruguay' : 'gut gut gdak',
 'Afrikaans' : 'kukeleku',
 'Korea' : 'ko-ko-ko',
 'Iceland' : 'Chuck-chuck!',
 'Albania' : 'Kotkot',
 'Algeria' : 'Cotcotcodet'
 }
 }
];

Otherwise with your version you're looping while looping when you can just simply check for existence.

Of course there are many ways to skin a cat, so the above is equivalent to

function petSounds(animal, country) {
 const noise = animalNoises.find(obj => obj.hasOwnProperty(animal))[animal][country];
 return `${animal}s in ${country} say ${noise}`
}

Of course if you are receiving this JSON from somewhere else you could do a reduction on it and then associate the keys and values into a super object(using Array#reduce() and Object.entries())

animalNoises = animalNoise.reduce((acc, obj) => {
 Object.entries(obj).forEach(([key, value]) => {
 acc[key] = value;
 });
 return acc;
 },
 {}
)
function petSounds(animal, country) {
 return `${animal}s in ${country} say ${animalNoises[animal][country]}`;
}

If you want to learn more about the cool things you can do with Arrays you should check out the MDN for JavaScript Arrays

The in operator is a really useful way to make Object#hasOwnProperty() shorter

And as always a lot more information about JavaScript can be found at the MDN


Some extra fun with Object Sestructuring for just another way to arrange things:

function petSounds(animal, country) {
 const { [animal]: { [country]: noise } } = animalNoises.find(obj => animal in obj);
 return `${animal}s in ${country} say ${noise}`
}
answered Nov 21, 2018 at 5:49

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.