0

I have the following array:

[
 0 [product_id, title, description]
 1 [1234, apple, this is just apple]
 2 [2345, pineapple, this is not just apple]
]

This array is long and product_id's can vary by a lot. I need to select an element based on it's product_id and update it's title and description.

Is there a way to do it without a for loop (such as for -> if product_id = id -> do something), since I will end up with n^2?

Thank you for your time.

9
  • 1
    Nope, not really, if you want the outer array based on it's content you have to iterate Commented Apr 29, 2015 at 23:19
  • 1
    Why not have a collection instead? [{id: 1, title: 'Foo', description: 'baz'}, ...] Commented Apr 29, 2015 at 23:20
  • 3
    Single scan of an array is O(n). Commented Apr 29, 2015 at 23:22
  • and how would I call a member of a collection without parsing through all the elements? Commented Apr 29, 2015 at 23:23
  • PM 77-1, but I always have an array of changes, so it is parsing 2 arrays Commented Apr 29, 2015 at 23:24

3 Answers 3

1
  • Assumption: product_id is unique

For an array there is no other way but to loop through it all. You should consider changing your datamodel into a JSON then it will become much easier.

In your example

var products = [
 0 [product_id, title, description]
 1 [1234, apple, this is just apple]
 2 [2345, pineapple, this is not just apple]
]

becomes

var products = {
    product_id: [product_id, title, description],
    1234: [1234, apple, this is just apple],
    2345: [2345, pineapple, this is not just apple]
}

Now you can simply say

var select_1234 = products[1234];

to get the product of 1234.

If you must stick with the array and you need to find products multiple times, consider doing a transform at the beginning of your app to change it into json. As such you have indexed your data and now you can again call

products[1234]

EDIT

Alternatively, you can create json data to link to your array for example

var productsIndex = {
    product_id: 0,
    1234: 1,
    2345: 2
}

This links to the position of the array so now you can call

var find = productsIndex[1234];
var select_1234 = products[find]; //This is the original array.

As an extra, consider using async transformations to transform the data so it does not freeze up any UI. This can be done using a recursive setTimeout with 0 seconds

var products = {
    product_id: [product_id, title, description],
    1234: [1234, apple, this is just apple],
    2345: [2345, pineapple, this is not just apple]
}

var productsIndex = {}

function recursiveTransform(val){
    setTimeout(function(){
        productsIndex[products[val].[0]] = val; //products[val].[0] is the product id of each array element
        if (val != products.length -1) recursiveTransform(val+1);
    }, 0)
}

recursiveTransform(0);

By doing this, you will not freeze up your ui or any other operation that might need to be run during the process

  • I haven't tested the code but it should give you an idea
Sign up to request clarification or add additional context in comments.

9 Comments

I can't use product_id as id, but thanks for the advice about transforming it to JSON - that might actually work
JSON is a dataformat for strings, I don't see how that helps, but maybe it's just me ?
@adeneo JSON is a key value data structure.
That would be a javascript object !
@user3078775 can you not use this method because product_id is not unique?
|
0

Use Array.prototype.find or Array.prototype.findIndex:

[
  [2439, 'title', 'description'],
  [1234, 'apple', 'this is just apple'],
  [2345, 'pineapple', 'this is not just apple']
].findIndex(function(a){return a[0] == 1234}); // returns 1

[
  [2439, 'title', 'description'],
  [1234, 'apple', 'this is just apple'],
  [2345, 'pineapple', 'this is not just apple']
].find(function(a){return a[0] == 1234}); // returns [1234, 'apple', 'this is just apple']

I’d recommend to simply use a polyfill as well. See the links: they offer polyfills for both so that Chrome and IE can support this as well.

7 Comments

Arrow functions can't be polyfilled.
You can use normal functions as well, I’ve edited the answer so that normal functions are used.
The polyfill is still a scan, though. If the concern is performance today, it's not the way to go. It'll be nice when ES6 starts to come online for real though.
@DylanWatt The two methods internally are scans as well so it doesn’t make a huge difference.
@Xufox, I would assume the "native code" scan should be more performant? If not, then it comes back to the fact the original question was how to avoid scanning.
|
0

There's no way to lookup like you want. You'll need to create a map. That map can either replace your initial array in your data, if it makes sense, or you can just generate a lookup map that you refer to later.

Luckily if you set fooarray[0] = bar;foomap['uuid'] = bar;, you can update bar via either data structure eg fooarray[0][1] = 'new title' or foomap['uuid'][1] = 'new title' and it will update in both structures, because it's passed by reference.

edit building on @YangLi:

var products = {
    product_id: [product_id, title, description],
    1234: [1234, apple, this is just apple],
    2345: [2345, pineapple, this is not just apple]
}

var productsIndex = {}

function recursiveTransform(val){
    setTimeout(function(){
        productsIndex[products[val].[0]] = products[val];
        if (val != products.length -1) recursiveTransform(val+1);
    }, 0)
}

recursiveTransform(0);

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.