3

I have a data structure like this:

var example = [
    { name: "item1", year: 2013, value: 100 },
    { name: "item1", year: 2012, value:  97 },
    { name: "item3", year: 2013, value:  93 },
    { name: "item3", year: 2012, value:  91 },
    { name: "item2", year: 2012, value:  -6 },
    { name: "item2", year: 2011, value:  -5 },
    { name: "item4", year: 2012, value: -36 },
    { name: "item3", year: 2011, value:  93 },
    { name: "item4", year: 2013, value: -35 },
    { name: "item1", year: 2011, value:  98 },
    { name: "item2", year: 2013, value:  -7 },
    { name: "item4", year: 2011, value: -37 },
    { name: "item5", year: 2013, value:  58 },
    { name: "item5", year: 2012, value:  55 },
    { name: "item5", year: 2011, value:  54 }
];

I am using this function to get an array of single elements:

example.reduce(function (prev, curr) {
    if (prev.indexOf(curr.name) === -1) prev.push(curr.name);
    return prev;
}, []);

While this works, I try to use a ternary operator for readability like this:

example.reduce(function (prev, curr) {
    return prev.indexOf(curr.name) === -1 ? prev.push(curr.name) : prev;
}, []);

and I get the following error in Chrome:

Uncaught TypeError: prev.indexOf is not a function
    at <anonymous>:3:13
    at Array.reduce (native)
    at <anonymous>:2:9
    at Object.InjectedScript._evaluateOn (<anonymous>:895:140)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:828:34)
    at Object.InjectedScript.evaluate (<anonymous>:694:21)

Why is that?

2
  • That is because push function doesn't return the same array. Commented Jun 9, 2015 at 4:02
  • 2
    That's because .push doesn't return an array. It returns the new length of the array. Commented Jun 9, 2015 at 4:02

2 Answers 2

5

it is because calling .push() will return the new length of the array which is a number, so the second call prev will be a number(1) which don't have the push method.

Returns

The new length property of the object upon which the method was called.

So using the if condition will be better in your case.

If you want to still use the ternary operator, you can use a hacky solution like

var b = example.reduce(function (prev, curr) {
    return prev.indexOf(curr['name']) === -1 ? prev.push(curr['name']) && prev : prev;
}, []);
Sign up to request clarification or add additional context in comments.

1 Comment

You can make your solution less hacky. See my answer above.
2

Replace your ternary operator with && and , instead of ? and : as follows:

example.reduce(function (prev, curr) {
    return prev.indexOf(curr.name) < 0 && prev.push(curr.name), prev;
}, []);

In this case, instead of using the ternary operator we use logical AND to test whether prev.indexOf(curr.name) < 0 and if so then we do prev.push(curr.name). However, we always return prev because of the comma operator.

As I mentioned in my comment, your code doesn't work because .push doesn't return the original array. It returns the new length of the array. You could replace .push with .concat but it would be very inefficient. The method I described above is better.

1 Comment

Thanks, although your answer is valid and i learned more on the comma operator, for readability I prefer to use the ternary operator. Will try to do a jsperf to see which one is best performing and will choose accordingly.

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.