3

If I have an array that look like this:

[
   {
       key: some_key,
       payload: { ... }
   }, 
   {
       key: some_key,
       payload: { ... }
   }, 
   {
       key: some_key,
       payload: { ... }
   }, 
   ...
]

and I want to find something using a key and then modify the payload.

Is there any way other than iterating through the array?

I have several concerns about iterating

  1. This array is used by many async functions, I am worried that the index might be invalidated by some other functions during the iteration.
  2. Iteration might lead to a lower performance.

I thought about using a immutable object there, but converting to array before every re-rendering doesn't seem very efficient.

Any good idea?

3
  • 1
    you will have to iterate anyway, unless you know the index of the element Commented Aug 5, 2017 at 23:46
  • Yeah iteration is really your only option here if you have no other point of reference Commented Aug 5, 2017 at 23:47
  • hmmm, so if I have no choice but do this iteratively. Then is there any way to do conflict resolution? because there are functions that will fire up be the server to modify this array on the fly. say I get a index here, then suddenly another element is inserted, does that make my function fail silently? Commented Aug 6, 2017 at 0:19

6 Answers 6

1

Another approach would be to pre-build a map by key of all your items. And pass it along the array.

{
  some_key: {
    key: some_key,
    payload: {}
  },
  some_other_key: {
    key: some_other_key,
    payload: {}
  },
  ...
}

You can still have the array as another representation of your data. The actual items, would be exact the same, because the map would just reference the real items in the list, but you could have the fastest possible access performance without searching at all.

This example shows, that the actual payload is still the same data, just another (indexed) representation of it.

const array = [
  { key: 'one' },
  { key: 'two' }
];

const map = array.reduce((acc, item) => {
  acc[item.key] = item;
  return acc;
},{});

array[0] === map.one // true
Sign up to request clarification or add additional context in comments.

4 Comments

this sounds like an good idea. So the array only keep the key and when I want to modify values I only modify them in the object right?
exactly, the key points to the reference of the that object, you change it inside the map, it's the same inside the array..
I think this should work. I will need to wrap it in some kind of object. Strange that there is no such kind of modules on github, looks like a mutable array could be useful.
Definitely, if you need to look up the same data very often, it would be the way to go.
0

Its just basic computer science. Unless you know things like the starting/ending index of at least close to the range you expect an item to be you have to search the entire space.

For your purposes, just using Array.filter should be good enough. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

Comments

0

There are a lot of ways, map

var arr = [
   {
       key: 1,
       payload: { }
   }, 
   {
       key: 2,
       payload: { }
   }, 
   {
       key: 3,
       payload: {}
   }
];

arr.map(function(e, i) {
  if(e.key === 1) {
    e.payload = {id: 11, name: "someone" }
  }
})
console.log(arr)

using findIndex

var arr = [
       {
           key: 1,
           payload: { }
       }, 
       {
           key: 2,
           payload: { }
       }, 
       {
           key: 3,
           payload: {}
       }
    ];
    var elementIndex = arr.findIndex(x => x.key === 1);
    if(elementIndex > -1)
        arr[elementIndex].payload = {id: 11, name: "someone"};
    console.log(arr)

And there are more options, depending on your needs :)

1 Comment

hmmm, separating key and details. I think this has become the mainstream in the answers. I will give it a try. I will give you a vote, good effort, thanks.
0

Instead of using an array with iteration, simply access values by key.

var hashtable = {};

// Setting a value...
hashtable["key"] = someValue;

// Getting a value...
var somePayload = hashtable["key"];

You can iterate through an associative array just fine, and if for some reason you can't simply change your array to an associative one, by far your simplest solution is to just keep an extra associative array as an index by your key.

Here's a tutorial on associative arrays in JavaScript. Good luck.

2 Comments

That's not really different. If we can remember the key we can remember the index.
@nem035 , there is absolutely no indication that array indexes are necessary for the OP's situation, and good reason to believe they aren't and that he/she simply doesn't know about associative arrays. There's no worry about "remembering" a key, since the OP explicitly asks to find a value by key. In addition, as you likely know, iterating through an associative array is bone-simple.
0

If you're willing to change the way the data is structured you can do something like this using Map:

var values = [
   {
       key: '4',
       payload: 'a'
   }, 
   {
       key: '5',
       payload: 'b'
   }, 
   {
       key: '6',
       payload: 'c'
   }, 
];

values = new Map(values.map(elem => [elem.key, elem]))

values.set('5', {key: '5', payload: 'x'});

console.log(values.get('5'));

Comments

0

The operation to find an element of an array when you do not know its position has to be linear at best. The worst case is still having to check every element.

As far as the array being used by multiple async functions, you could still build a mechanism that will affect the array in certain order, no matter in which order the actual async operations finish.

Promises are a natural fit here.

const array = [];

// these operations start at the same time
const p1 = new Promise(resolve => resolve(1));
const p2 = new Promise(resolve => resolve(2));

// no matter which one finishes first,
// we process p2 before p1 because of
// the way we build the chain
p2
.then(p2Result => {
  array.push(p2Result)
  return p1;
})
.then(p1Result => {
  array.push(p1Result);
  return array;
})
.then(console.log);

2 Comments

Is promise a blocking call? tbh I haven't used promise in a non-async call before. I will upvote you. I think promise is a good call.
@TyanHauChiau No, promise is by nature async, it cannot be sync.

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.