13

My rest API returns with the following json content:

[{
    "key": "apple",
    "value": "green"
},
{
    "key": "banana",
    "value": "yellow"
}]

I am iterating through the list with this code:

this.props.json.map(row => {
    return <RowRender key={id.row} row={row} />
}

It works because the content is displayed but on the web browser's console I can see an error:

map is not a function

I googled for it and I changed my code to this:

Array.prototype.slice.call(this.props.json).map(row => {
    return <RowRender key={id.row} row={row} />
}

It works without any error but seems so complicated. Is that the correct way to do this job?


UPDATE

What I tried:

  • JSON.parse(...).map: Unexpected end of JSON input
  • JSON.parse(JSON.stringify(...)).map(...): data is displayed but I get an error: JSON.parse(...).map is not a function
  • Array(...).map: Each child in array or iterator should have a unique key.
7
  • What exactly is this.props.json…? How does it get created? { ... }, { ... } is neither valid JSON nor Javascript.
    – deceze
    Commented Jan 17, 2017 at 17:00
  • Instead of using Array.prototype.slice.call(this.props.json) you can use Array(this.props.json), but anyway it looks like it's something wrong with your application. Is that complete output from your API? Commented Jan 17, 2017 at 17:02
  • 1
    updated. now it looks better
    – zappee
    Commented Jan 17, 2017 at 17:02
  • Now your JSON response is valid, I can post solution, but the questions is holded. Commented Jan 17, 2017 at 17:09
  • 1
    please check my updated post
    – zappee
    Commented Jan 17, 2017 at 17:28

5 Answers 5

44

Use Object.entries() to get both the key and values, then give that to Map() to allow you to select your values by key.

let myMap = new Map(Object.entries(this.props.json));
9

in your code this.props.json is not an array, it's an array-like object and map is an array function. what your doing to solve this, is converting that array-like object into an array, with .slice()

a more elegant way to do this:

Array.from(this.props.json).map(row => <RowRender key={id.row} row={row} />)
4

You can do it very easily as @Gary mentioned in his answer:

From Map to JSON (string keys):

const personsJson = `{"1":{"firstName":"Jan","lastName":"Kowalski"},"2":{"firstName":"Justyna","lastName":"Kowalczyk"}}`;
const personsObject = JSON.parse(personsJson);
const personsMap = new Map(Object.entries(personsObject));
for (const key of personsMap.keys()) {
    console.log(typeof key)
}

But there is one issue about which you have to be careful. Key of the map created in that way will always be a STRING. It will happen, because KEY of JSON object is always a STRING. So if your Map keys should be numbers then first you have parse keys of your object entries.

  • From JSON to Map (number keys)::

const personsJson = `{"1":{"firstName":"Jan","lastName":"Kowalski"},"2":{"firstName":"Justyna","lastName":"Kowalczyk"}}`;
const personsObject = JSON.parse(personsJson);
const personObjectEntries = Object.entries(personsObject);
const personObjectEntriesNumberKeys = personObjectEntries.map(person => {
    person[0] = parseInt(person[0]);
    return person;
});
const personsMap = new Map(personObjectEntriesNumberKeys);
for (const key of personsMap.keys()) {
    console.log(typeof key)
}

There is person[0] because under 0 index there is the key of the object

4
let jsonMap = JSON.stringify([...map.entries()])
let myMap = new Map(JSON.parse(jsonMap));
5
  • 4
    Please add an explanation, highlighting parts of your answer that addresses OP's issue, and why/how. Code only answers are generally frowned upon on SO . Adding details adds to long term value, and helps future visitors learn, so they can apply this knowledge to their own coding issues. Also, it improves quality of the answer, and hence SO as well. Higher quality answers are upvoted more often, as more users find them of greater use as a resource to refer back to. Consider editing to provide additional info. Commented Jul 7, 2020 at 14:52
  • 1
    It makes no sense to serialize and then immediately deserialize an object.
    – Shanerk
    Commented Mar 3, 2021 at 22:49
  • @ShaneK it's a pretty good unit test whenever you are dealing with parsers and (pretty) printers of any kind.
    – bash0r
    Commented Oct 9, 2021 at 22:21
  • @Shanerk The point of serializing and immediately deserializing immediately is to give a concise example of doing all possible related actions in both directions. These 2 lines answered all 4 of my questions. Commented Aug 25, 2023 at 0:27
  • 1
    The prior answer by @Gary is much better. It is a sadly common anti-pattern I see all the time when refactoring code where less experienced programmers convert everything to strings and use JSON serialization as a lazy way to get around understanding the object model.
    – Shanerk
    Commented Aug 28, 2023 at 16:06
0

You can copypaste this function: it would take JSON and return a Map of Maps:

It works with this JSON:

{
   "data":{
      "1":{
         "color":"red",
         "size":"big"
      },
      "2":{
         "color":"red",
         "size":"big"
      },
      "3":{
         "color":"red",
         "size":"big"
      },
      "4":{
         "color":"red",
         "size":"big"
      },
      "5":{
         "color":"red",
         "size":"big"
      }
   }
}
function jsonToMap(jsonString)  {
    var jsonObject = JSON.parse(jsonString);
    var dataObject = jsonObject.data;
    var dataMap = new Map(Object.entries(dataObject));
    var resultMap = new Map();
    for (const key of dataMap.keys())  {
        console.log(key);
        var keyMap = new Map(Object.entries(dataMap.get(key)));
        resultMap.set(key, keyMap);
    }

    console.log("done!");
    return resultMap;
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.