comparing two objects and finding the missing fields with java - java

I want to find the the recipes from the users provided ingredients
and tell the user the missing ingredient from the main recipe's ingredients
how can i find the missing ingredients ? i mean how should I query to to comparing ?
{
"ingredients":[
{"title":"apple"},
{"title":"cheese"},
{"title":"banana"},
{"title":"orange"},
]
}
The second would be :
[
{"title":"apple"},
{"title":"cheese"},
]
It should give us the missing two others like :
{"title":"banana"},
{"title":"orange"},

I'm not sure what objects you intend to use, but if each object possessed a Set of these values, you could find the difference as per Prabhaker A's answer here like so:
Set<String> objectASet = new HashSet<>(Arrays.asList("apple", "cheese", "banana", "orange"));
Set<String> objectBSet = new HashSet<>(Arrays.asList("apple", "cheese"));
Set<String> differenceSet = objectASet.removall(objectBSet);
This will change the values of object A's set, however, so a copy will need to be made to preserve those values.

Related

Validate facts having nested maps using drools

I have a class Fact which is a extends java.util.HashMap class. I am passing object of this class as fact to drools.
Now an instance of fact looks like this (Map<String, Object>):
{
"key1": "value"
"attributes": [{"name": "name1", "value": "value1"},{"name": "name2", "value": "value2"},{"name": "name3", "value": "value3"}...]
"locks": [{"type": "type1", "value": "value1", "attributes": {"key_a1": "val_a1""key_a2": "val_a2"...}}]
}
Running validations on root level entries in this map is straight forward e.g. running validations on key1.
Now, I want to run some validations on attributes and locks.
For attributes, I want to ensure that all attributes which are needed are present in this map and their corresponding values are correct. So I do this in the when block:
fact: Fact(this["key1"] != null && this.containsKey("attributes"));
attributesEntries: Entry(key == "attributes") from fact.entrySet();
attributesMaps: LinkedHashMap() from attributesEntries;
fact is HashMap
attributes are of type ArrayList<LinkedHashMap<String, String>> (an id key is also added for the LinkedHashMap whose value is the value of key name only).
locks are of type ArrayList<LinkedHashMap<String, Object>>
locks have attributes of type Map<String, String>
but it is not working. When I evaluate attributesEntries it is ArrayList<LinkedHashMap> and it has all the expected values but attributesMaps comes as empty. I also tried passing filters like LinkedHashMap(key == 'key1', value == 'val1') but that also didn't work. Tried looking for solutions and none were available for this sort of structure. Whatever was available I tried to extend but didn't work.
Is this possible to achieve and if so how? Also, how do I validate value (not empty and matches a pattern) once I am able to get it from the Map.
I am new to drools and we are using 5.4.0.Final version of drools.
Also, how can I work with the next level nested Map in locks.
I once had the misfortune of working on a project where we made this same mistake and had our class extend HashMap. (Fair warning: HashMap doesn't serialize well so you're going to use a lot of extra memory.)
I'm going to assume several things about your model because you neglected to share the class definition itself.
But I'm going to assume the following, based on your example JSON:
You have added a string value ("value") with the key "key1"
You have added a List<Map<String, ?>> value (possibly a List<Fact>) with the key "locks"
You have added a List<Map<String, ?>> value (possibly a List<Fact>) with the key "attributes"
The HashMap's get(key) method will return an object value; you've already noted the special this[ key ] syntax.
From your partial rule attempt, it's not entirely clear what you're trying to do. I think you're trying to get the List<Map<String, ?>> that is saved in your map under the "attributes" key.
rule "Do something with the attributes"
when
$fact: Fact( this["key1"] != null,
$attr: this["attributes"] != null )
then
System.out.println("Found " + $attr.size() + " attributes");
end
this["attributes"] returns the value associated with the key attributes. In this case, it's a List or whatever you shoved in there. If the key doesn't exist, the null check handles that.
You also asked how you could do stuff with a child map inside one of those lists. Let's say that want to do something with the attribute that has "name": "name1" ...
rule "Do something with the 'name = name1' attribute"
when
$fact: Fact( this["key1"] != null,
$attributes: this["attributes"] != null )
$nameAttr: Map( this["name"] == "name1" ) from $attributes
then
// do something with $nameAttr
end
The pattern repeats, of course. Let's say you've shoved yet another List<Map<String, ?>> into your attribute maps:
rule "Do something with a child of 'name' attribute"
when
$fact: Fact( this["key1"] != null,
$attributes: this["attributes"] != null )
$nameAttr: Map( this["name"] == "name1",
$attrKids: this["children"] != null ) from $attributes
$childNameAttr: Map( this["name"] == "child1" ) from $attrKids
then
// etc.
end
I strongly recommend reconsidering your object model to not be Map-based. At the company I worked at where all of our projects were built against a nested Map-based model and running Drools 5.0.1, I spent significant time and effort upgrading parts of it to Drools 7 and a proper model that passed in just the data we needed. It saved a ton of resources and ended up being much faster.

Multi-Dimensional Array(or other structure) in Java

I come from PHP, i'm developping a tool, and i need to use a multidimensional array ( or something other, map,..)
My goal is to be able to have an ArrayList like that :
[["name1", "surname1", "age"], ["name1", "surname1", "age"]]
Or :
[["name" : "name1", "surname" : "surname1", "age" : "age1"], ["name" : "name2", "surname" : "surname2", "age" : "age2"]]
And to be able to add another list into this global list, without size limit.
Actually, i do not found that in Java, it's crazy xD.
The goal after that it to filter (with something like in PHP ((multi sort) to be able to sort those arrays which areinside the global array.
( I need to sort a key of those list,in order to get the most recent, and then i save the first list which is the most recent ).
So actually, i only arrive to get an arraylist.. but not multidimensionnal..
Thanks for tips :)
(I use spring boot )
EDIT 1 :
HashMap<String, String> myhash = new HashMap<String, String>();
myhash.put("Cat1", "james");
myhash.put("Cat2", "adams");
myhash.put("Cat3", "turk");
System.out.println(myhash);
// {Cat3=turk, Cat2=adams, Cat1=james}
// I Would like : [{Cat3=turk, Cat2=adams, Cat1=james}, {Cat3=turkother, Cat2=adamsother, Cat1=jamesother}, {Cat3=fred, Cat2=ded, Cat1=tp}]
You mean HashMap<String, ArrayList<String>> and than use filter on the HashMap.keyset().
But don't know if this is exactly what your are looking for.
Two notes:
This is basic Java. No Spring required.
If you make a nice Java object with the properties you are looking for, perhaps filtering will be more easier... But don't know. I would create an object Person with the required properties, store it in an ArraysList and than use this object further.
Update:
HashMap<String, String> myhash = new HashMap<String, String>();
myhash.put("Cat1", "james");
myhash.put("Cat2", "adams");
myhash.put("Cat3", "turk");
System.out.println(myhash);
// {Cat3=turk, Cat2=adams, Cat1=james}
// I Would like : [{Cat3=turk, Cat2=adams, Cat1=james}, {Cat3=turk, Cat2=adams, Cat1=james}]
ArrayList<HashMap<String, String>> lst = new ArrayList<>();
lst.add(myhash);
lst.add(myhash);
System.out.println(lst); //[{Cat3=turk, Cat2=adams, Cat1=james}, {Cat3=turk, Cat2=adams, Cat1=james}]
Remark:
take care that myhash is added twice ==> if you change on the one field ==> changes on the other field is done as well
I don't see much value in this sample. Especially since the Map is added twice.
Take a look at the different samples for streams - for filtering and sorting. This might be useful.
If there are more qs I would guess its better to create a different q. I think that's it ... Feel free to ask ...
Here is how you have a list of lists in Java.
ArrayList<ArrayList<String>> myList = new ArrayList<>();

How to use distinct/aggregate to get all fields that match several queries

I just learned how to use distinct.
What I do is create a BasicDBObject, put as query parameter to distinct what I want to be equal, and as field parameter what I want returned.
Now I want to do something similar, but with several queries. That meaning, I want the query to match several keys of the document (id and date have to be the same as the input I get), and return what sessions match that in the collection.
I tried doing something similar to find, but for distinct, where you add with append() or put() more fields to the query parameter.
This syntax does not seem to work and I found no one using similar code, so I guess it's not possible.
I've found the aggregate() method, but it seems to be used to match several FIELDS, not queries. Explanation with code:
array.put(coll.distinct(field, query));
I want that query parameter to have several keys, so that all fields match my input, and I find unique values of field that match both (or as many) keys in query.
Thanks in advance!
Edit:
Basics: MongoDB 3.2.2
Data manipulation:
"Session" : "value1", "car" : "carNumber", "date" : "20130321"
I have a very large collection with a number of documents that have, among other keys, this ones. I want, given a car and a number, get every UNIQUE session value, and return it as a json (for which, so far, I put the values into an array, and transform into json).
driver/framework specific question: I do not know to query this in mongodb shell. I know to use distinct, but not aggregators.
There are multiple parts in your question. I would like to answer the last part which is highlighted in bold. The solution is written in Java as the thread is tagged as Java.
The below code would give you the distinct session values for a car and car number. You can change the filter accordingly for your requirement.
The below code satisfies the basic distinct concept for your requirement. I assume that you can add code to result set into JSON (you can use Jackson or Gson libs for generating JSON).
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
public class MongoReadDistinct {
public static void main(String[] args) {
MongoClient client = new MongoClient();
MongoDatabase database = client.getDatabase("cars");
MongoCursor<String> mongoCursorIds = database
.getCollection("sessions").distinct("Session",
Filters.and(Filters.eq("car", "Nisson_Note"), Filters.eq("carnumber", 123)), String.class)
.iterator();
while (mongoCursorIds.hasNext()) {
System.out.println(mongoCursorIds.next());
//You can convert the result to JSON
}
}
}
Sample Data:-
/* 1 */
{
"_id" : ObjectId("576a6860d317ab85059c76d4"),
"Session" : "value1",
"car" : "Nisson_Note",
"carnumber" : 123,
"date" : "20130321"
}
/* 2 */
{
"_id" : ObjectId("576a6896d317ab85059c76d5"),
"Session" : "value2",
"car" : "Nisson_Note",
"carnumber" : 123,
"date" : "20130321"
}
/* 3 */
{
"_id" : ObjectId("576a68b4d317ab85059c76d6"),
"Session" : "value2",
"car" : "Nisson_Note",
"carnumber" : 123,
"date" : "20140321"
}
Output:-
value1
value2
Well, to answer my own question, it is actually possible to have several queries in distinct method, it can be done both in mongodb shell and in java driver (unfortunately I did not get the other answer to work, not that is wrong, I just didn't manage).
So for mongodb shell (I include it because I didn't know to do this, either, which was part of the problem):
db.colectionLocalCC.distinct("Session", {date: "20130303", Car: "55"})
And for mongodb:
BasicDBObject query = new BasicDBObject();
query.put("date", date);
query.put("car",car);
String fields = "Session";
array.put(coll.distinct(fields, query));

How to acquire the Key/name of root level JSON Objects with JSONPath?

So I have been using jayway JSONPath to query JSON Objects much like the following:
{
"messageHeader" : {
"sentBy" : "someOne",
"userName" : "John Doe"
},
"payload" : []
}
And this is working fine for the most part, except now I wish to select the root level objects using the path $..* and preform separate tasks depending on the type of object present in the message, using their key/names as an identifier.
However, using said path, or $.* , will always produces a JSONArray much like this:
[{sentBy:someOne,userName:John Doe},[]]
The JSON objects appear to be anonymous, they have no keys. Is there anyway I can access the key for these objects directly as a String? If the data is not present, then why does the path: $.messageHeader.sentBy , work?
From README of the JsonPath :
When evaluating a path you need to understand the concept of when a
path is definite. A path is indefinite if it contains:
.. - a deep scan operator
?() - an expression
[, (, )] - multiple array indexes
Indefinite paths always returns a list (as represented by current JsonProvider).
This should explain the above phenomenon.

Easiest way to extract fields from JSON

Update: I should have mentioned this right off the bat: I first considered a Java/JSON mapping framework, but my manager does not want me adding any more dependencies to the project, so that is out as an option. The JSON-Java jar is already on our classpath, so I could use that, but still not seeing the forest through the trees on how it could be used.
My Java program is being handed JSON of the following form (althought the values will change all the time):
{"order":{"booze":"1","handled":"0","credits":"0.6",
"execute":0,"available":["299258"],"approved":[],
"blizzard":"143030","reviewable":["930932","283982","782821"],
"units":"6","pending":["298233","329449"],"hobbit":"blasphemy"}}
I'm looking for the easiest, efficient, surefire way of cherry-picking specific values out of this JSON string and aggregating them into a List<Long>.
Specifically, I'm looking to extract-and-aggregate all of the "ids", that is, all the numeric values that you see for the available, approved, reviewable and pending fields. Each of these fields is an array of 0+ "ids". So, in the example above, we see the following breakdown of ids:
available: has 1 id (299258)
approved: has 0 ids
reviewable: has 3 ids (930932, 283982, 782821)
pending: has 2 ids (298233, 329449)
I need some Java code to run and produce a List<Long> with all 6 of these extracted ids, in no particular order. The ids just need to make it into the list.
This feels like an incredibly complex, convoluded regex, and I'm not even sure where too begin. Any help at all is enormously appreciated. Thanks in advance.
The easiest way IMO is use a json library such as gson, jackson, json.org, etc, parse de JSON into an object and create a new List<Long> with the values of the properties you need.
Pseudocode with gson:
class Order {
long[] available;
long[] approved;
...
}
Order order = gson.fromJson("{ your json goes here }", Order.class);
List<Long> result = new ArrayList<Long>();
result.add(order.getAvailable());
result.add(order.getApproved());
...
Pseudocode with json.org/java:
JSONObject myobject = new JSONObject("{ your json goes here"});
JSONObject order = myobject.getJSONObject("order");
List<Long> result = new ArrayList<Long>();
for (int i=0; i<order.getJSONArray("approved").length(); i++) {
Long value = order.getJSONArray("approved").getLong(i);
result.add(value);
}
...

Categories