0

extension of this question

So I was playing around with a project and I found myself needing to create a string where I didn't know the exact order of the lettering right away, but I did know their position(and by extension, the length of this string).

Part of the reason for doing it this way is that I don't want to skip array elements at any point during the process(NO ["a", , "t"] during the process). Meaning that the order of insertion matters.

let string_length = 10;

let o = {
  0: "a",
  4: "q",
  7: "t",
  3: "p",
  6: "h",
  1: "z",
  2: "t",
  5: "a",
  9: "b",
  8: "z"
};

function obj_to_arr(o) {
  // this returns ["a","z","t","p","q","a","h","t","z","b"]
}

All the answers I've found until now don't necessarily guarantee that given an index object, it will give the corresponding ordered object, and this is mainly because of the nature of object, being unordered.

Is there a way to implement this?

Jaacko Torus
  • 796
  • 7
  • 24
  • 3
    Stack Overflow generally prefers questions to statements ;-) – jarmod Mar 21 '19 at 23:05
  • To echo that... what's the actual question? – Mike 'Pomax' Kamermans Mar 21 '19 at 23:06
  • Sorry, I forgot to write it:P – Jaacko Torus Mar 21 '19 at 23:07
  • 1
    You mean the built in [Object.keys()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) and [Object.entries()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) functions? – Mike 'Pomax' Kamermans Mar 21 '19 at 23:08
  • @Mike'Pomax'Kamermans but you can't really make sure that the array outputted will be ordered like written – Jaacko Torus Mar 21 '19 at 23:09
  • 1
    If the order of insertion is important, then you're absolutely using the wrong datastructure here. Use an object only if you don't care about the key-value ordering, because the spec literally makes _no_ guarantee that there even _is_ an ordering. That's entirely up to the JIT to decide. Once that `let o` gets stored in memory, those keys have zero obligation to reflect the ordering you wrote down and will in fact more than likely be stored in a sorted fashion, so that property lookups on your object can use an efficient resolution algorithm. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:13
  • @Mike'Pomax'Kamermans this object is generated, and the exact order is not known from the beggining, I used a literal because it is most concise in this question. The problem is that when the object is generated the elements order is not known, then I plan to make it into an array and make sure that the order of insertion is correct. – Jaacko Torus Mar 21 '19 at 23:16
  • Again: if the order matters, don't use an object. Don't generate what you're showing here, and instead generate, for instance, an array of tuples, which *is* guaranteed to preserve ordering. And if you don't control the generating code, then expecting to be able to rely on the object keys staying ordered-as-declared is expecting something that javascript simply doesn't do. If the _intent_ of that data is to be ordered, contact whoever generates it. They're doing something wrong here. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:17
  • @Mike'Pomax'Kamermans I've never heard of tuples – Jaacko Torus Mar 21 '19 at 23:19
  • 1
    tuples are a generic name for any collection of things that are supposed to be "kept together", so in this case you want something like `let properlist = [ {key: 0, value: `a`, {key: 4, value: `q`}, ...]` and now you _can_ rely on the fact that both the keys and values will always have the same order when you iterate. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:21

3 Answers3

-1

Using Object.keys(), you can retrieve an array of keys, sort them numerically, then map that sorted array to one with the values.

The result will be an array of values in an order corresponding to the numeric values of the keys, even if they are not sequential.

For example

let o = {"0":"a","1":"z","2":"t","3":"p","4":"q","5":"a","6":"h","7":"t","8":"z","10":"b"}

let sortedValues = Object.keys(o)
    .sort((a, b) => a - b)  // numeric comparison
    .map(k => o[k])         // map to values

console.info(sortedValues)
Phil
  • 157,677
  • 23
  • 242
  • 245
  • 2
    `Object.keys` does not guarantee the keys weren't reordered when the object was committed to memory by the JIT, though. Sorting won't restore the original ordering in this case. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:22
  • @Mike'Pomax'Kamermans I was under the impression that OP wanted the keys numerically ordered. That's why I sort them. This seemed clear to me in the desired output – Phil Mar 21 '19 at 23:42
-1

You could fix this in two possible ways (and probably more).

Array

Either you add objects containing both the key and the value to an array.

array.push({c: "a"}) or array.push({ key: c, value: "a"}), then add the next and so on.

Push puts an element at the end of an array.

Sorted object

Or you insert into the object using alphabetic keys, in which case you can use the example below.

You could sort the keys (properties) of the object, and use them to access each value and put them into another array. Here's a verbose example of how you could do that.

const someObject = {
  c: "a",
  4: "q",
  7: "t",
  b: "p",
  6: "h",
  1: "z",
  2: "t",
  5: "a",
  a: "b",
  8: "z"
};


function obj_to_arr(obj) {
  let result = []
  
  // Get keys from object as an array
  let keys = Object.keys(obj)
  console.log('keys: ', keys)
  
  // Sort the array in alphabetical order
  let sorted = keys.sort()
  console.log('sorted: ', sorted)
  
  // Add each value to the resulting array
  sorted.forEach(function(key) {
    console.log('adding ' + obj[key] + ' to array')
    result.push(obj[key])
  })

  console.log('result: ', result)
  return result
}

// Call the function
obj_to_arr(someObject)
Webber
  • 4,672
  • 4
  • 29
  • 38
  • Just as the other answers that already suggested `Object.keys()`, that function does _not_ guarantee keys in the same order they were declared. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:26
  • 1
    because you didn't read the post: they want the ordering that they declared, which is not alphanumerically sorted at all. Neither the keys, nor the values, follow a standard ordering. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:28
  • Noted, I edited my answer to actually answer the question. Thanks for your comment. – Webber Mar 21 '19 at 23:37
  • Note that the default lexicographic sorting of `Array.prototype.sort()` will mean key "10" comes before key "2" – Phil Mar 21 '19 at 23:45
  • Very true. In this case you could use a custom [sorting function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Examples). – Webber Mar 21 '19 at 23:57
-4

The short answer is "you can't" because of the Javascript spec.

Objects in Javascript are not guaranteed to have their keys ordered in any way due it being a primitive type that engines are allowed to optimize the hell out of, including reordering keys to speed up property access.

If ordering really matters, then you shouldn't be using an object primitive. Either an array of tuples (which has guaranteed ordering):

let fixedList = [
  { key: 0, value: 'a' },
  { key: 4, vlaue: 'q' },
  ...
];

or you can use a Map, which exists specifically as a way to have "an object, with the same ordering of key/value pairs as you declared".

Of the two, for data transport you probably want the former, and for running code you typically want the latter.

Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
  • 1
    the original order doesn't matter. That's the point. `o` is going to be generated in some order that I don't know, when the length reaches 10 or `string_length`, then I run the function which will order them. When creating the new array, the order of insertion does matter. – Jaacko Torus Mar 21 '19 at 23:34
  • and it will oder them _how_? Not "using what code", but "what ordering do you need to have happen, before you insert things into your fixed-ordering array"? – Mike 'Pomax' Kamermans Mar 21 '19 at 23:36
  • that's why I'm asking if it can be implemented, from what I'm getting it doesn't seem to be possible – Jaacko Torus Mar 21 '19 at 23:36
  • If _what_ can be implement though? Because your post asks about the ordering as specified in an object, so if you want that ordering then this answer is the _only_ answer: it cannot be done, because there _is_ no ordering of object keys. Object literals in Javascripts don't have ordered keys, so there is no ordering to find: there is none. Of course, if that is not what you're asking, then please edit your question and I can edit my responses accordingly. – Mike 'Pomax' Kamermans Mar 21 '19 at 23:38
  • 2
    I'm sorry for the confusion, but what I am pretty sure the question asks and what I'm trying to say is: given an unordered indexed object, how(if possible) can you make it into and array without skipping values – Jaacko Torus Mar 21 '19 at 23:41
  • Then please: update your post to say that, because that's not related to "ordering" in any way, that's related to "how do I turn something into an array without `undefined` in it". To be a [a good question](/help/how-to-ask), describe the actual problem, then show an example of that problem (so with an object you can show goes goes wrong), the result you want, the result you got instead, and what you tried to fix that (but didn't work) because right now that is still not the case. You're asking about orderings and you're linking to a different question instead of having all the details here. – Mike 'Pomax' Kamermans Mar 22 '19 at 18:06