Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

concatenate objects #252

Closed
mlund opened this issue May 26, 2016 · 14 comments
Closed

concatenate objects #252

mlund opened this issue May 26, 2016 · 14 comments

Comments

@mlund
Copy link

mlund commented May 26, 2016

Hi!
I wish to concatenate two json objects and thought of this:

#include <json.hpp>
#include <iostream>

int main() {
  nlohmann::json a,b;

  a[ "sec" ] = {
    { "title", "some title" }, 
    { "cnt", 10 }
  };

  b[ "sec" ] = {
    { "more info", "add something more" }
  };

  a += b;

  std::cout << a.dump(4);
}

which however throws an exception with v1.1.0. Any suggestions how to best do this?
Best, Mikael

@nlohmann
Copy link
Owner

The exception "cannot use push_back() with object" is due to the fact that a += b; is executed as a.push_back(b);, and push_back is only valid for arrays (see its documentation.)

(You originally reported a segmentation fault, and I was worried there was a bug ;-))

Unfortunately, the requested functionality is not present at this moment. Looking at Stack Overflow, it seems that std::map::insert can have similar effects. Maybe overloading nlohmann::json::insert accordingly could help. Any thoughts about this?

@mlund
Copy link
Author

mlund commented May 27, 2016

Thanks for quick response and sorry about the initial text; no bugs indeed! I actually do not know how to achieve what I want, regardless of syntax and I wonder if it's possible to add new objects to a["sec"] from another object? The insert() method does not allow objects if I understand it correctly. Concretely I have a json object created by a base class, and I need derived classes to add specific information to it.
I suppose STL-like merging using i.e. a.insert(b.begin(),b.end()) as for maps would be ideal, alternatively a << b?

@nlohmann
Copy link
Owner

Hi @mlund, you can achieve merging objects with the following function:

json merge(const json &a, const json &b)
{
    json result = a.flatten();
    json tmp = b.flatten();

    for (json::iterator it = tmp.begin(); it != tmp.end(); ++it)
    {
        result[it.key()] = it.value();
    }

    return result.unflatten();
}

It is based on the flatten()/unflatten() functions and has the single limitation that empty arrays and objects are replaced by null.

I hope this helps!

@mlund
Copy link
Author

mlund commented May 29, 2016

Thanks! Alternatively, this also worked for my purpose:

for (auto it=b["sec"].begin(); it!=b["sec"].end(); it++)
    a["sec"].push_back( json::object_t::value_type(it.key(), it.value())  );

@slabonia
Copy link

slabonia commented Jul 7, 2017

Hi, is this usefull for include one json object into other? i've get some errors 😞

@nlohmann
Copy link
Owner

nlohmann commented Jul 7, 2017

This basically implements the similar insert functions of std::map (http://en.cppreference.com/w/cpp/container/map/insert) and std::vector (http://en.cppreference.com/w/cpp/container/vector/insert).

@slabonia
Copy link

slabonia commented Jul 7, 2017

Thats greate!

No, i need to concatenate one json object into a specific index of another, something like:

Entities["table"] = mergeJSON(Entities, ReadedEntity);

Where mergeJSON is the merge function what i getted from this topic.

How can i do that?

@nlohmann
Copy link
Owner

nlohmann commented Jul 7, 2017

Could you provide an example for Entities and ReadedEntity?

@slabonia
Copy link

slabonia commented Jul 7, 2017

Entities:

{"CSVMsg": {
 "name": "PacketEntities",
 "class":35,
 "id":2,
 "serial":782
 }
}

ReadedEntity:

{"table":
 {"name": "DC_Player",
  "fields": {
   "0": {"m_flSimulationTime": 47},
   "1": {"m_nTickBase": 160748},
   "2": {"m_vecOrigin": {
    "0": 299.141327,
    "1": 2343.210938
    },
   },
   "3": {"m_vecOrigin2": -250.849808}
  }
 }
}

Need something like:

{"CSVMsg": {
 "name": "PacketEntities",
 "class":35,
 "id":2,
 "serial":782,
 "table":
  {"name": "DC_Player",
   "fields": {
    "0": {"m_flSimulationTime": 47},
    "1": {"m_nTickBase": 160748},
    "2": {"m_vecOrigin": {
     "0": 299.141327,
     "1": 2343.210938
     },
    },
    "3": {"m_vecOrigin2": -250.849808}
   }
  }
 }
}

@nlohmann
Copy link
Owner

nlohmann commented Jul 7, 2017

For your example, the following should do:

Entities["CSVMsg"]["table"] = ReadedEntity["table"];

@slabonia
Copy link

slabonia commented Jul 7, 2017

I don't test it already, but you are a kind of genius for my. Thank you a lot!

@Dariusz1989
Copy link

Dariusz1989 commented Jul 29, 2017

Hey
Not sure of how much of this is correct as I'm new to C++ but the original nlohmann post about merge produced issues with empty arrays as it converted them to null.. I did this little tweak to his code and now I can merge json files with empty arrays...

json merge(const json &a, const json &b)
{
    json result = a;
    json tmp = b;
    for (json::iterator it = tmp.begin(); it != tmp.end(); ++it)
    {
        result[it.key()] = it.value();
    }
    return result;
}

@nlohmann
Copy link
Owner

We discuss a merge operation for objects in #661.

@gregmarr
Copy link
Contributor

@Dariusz1989 FYI, the json tmp = b; there should not be necessary, you should just be able to use b directly to avoid copying b unnecessarily, which can be expensive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants