HashMap: Find next lower key - java

I am currently storing marshalling libraries for different client versions in a HashMap.
The libs are loaded using the org.reflections API. For simplicity sake I'll just insert a few values here by hand. They are unordered by intent, because I have no influence on in which order the map is initialized on start-up by the reflections API.
The keys (ClientVersion) are enums.
HashMap<ClientVersion, IMarshalLib> MAP = new HashMap<>();
MAP.put(ClientVersion.V100, new MarshalLib100());
MAP.put(ClientVersion.V110, new MarshalLib110());
MAP.put(ClientVersion.V102, new MarshalLib102());
MAP.put(ClientVersion.V101, new MarshalLib101());
MAP.put(ClientVersion.V150, new MarshalLib150());
All and well so far, the problem now is, that there are client versions out there where the marshalling did not change since the previous version.
Let's say, we have a client version ClientVersion.V140. In this particular case I am looking for MarshalLib110, assigned to ClientVersion.V110.
How would I get the desired result (without iterating through all entries and grabbing "the next lower" value each time)?
Thanks in advance!

How would I get the desired result (without iterating through all entries and grabbing "the next lower" value each time)
There is nothing you can do about "iterating through all entries" part: since the map is unordered, there is no way of finding the next smaller item without iterating the entire set of keys.
However, there is something you can do about the "each time" part: if you make a copy of this map into a TreeMap, you would be able to look up the next smaller item by calling the floorEntry method.
Another alternative is to copy the keys into an array on the side, sort the array, and run a binary search each time that you need to look up the next smaller key. With the key in hand, you can look up the entry in your hash map.

I recommend you to use NavigableSet. Look at this example:
HashMap<Integer, String> map = new HashMap<>();
map.put(100, "MarshalLib100");
map.put(110, "MarshalLib110");
map.put(102, "MarshalLib102");
map.put(101, "MarshalLib101");
map.put(150, "MarshalLib150");
NavigableSet<Integer> set = new TreeSet<>(map.keySet());
Integer key = set.lower(150); // ^ -> 110
String val = map.get(key); // ^ -> MarshalLib110
// or
key = set.higher(110);// ^ -> 150
val = map.get(key); // ^ -> MarshalLib150
Update: Using TreeMap to find next lower key is not really correct. Example:
TreeMap<Integer, String> treeMap = new TreeMap<Integer, String>();
treeMap.put(100, "MarshalLib100");
treeMap.put(110, "MarshalLib110");
treeMap.put(102, "MarshalLib102");
treeMap.put(101, "MarshalLib101");
treeMap.put(150, "MarshalLib150");
System.out.println(treeMap.floorKey(102));
System.out.println(treeMap.floorEntry(102));
System.out.println(treeMap.ceilingKey(102));
System.out.println(treeMap.ceilingEntry(102));
Output:
102
102=MarshalLib102
102
102=MarshalLib102

Related

Java 11 Filter a String entry from an Array of String does not work

I would like to remove a String entry and an empty String from the Array of Strings.
My array of String contains the following values from index 0 to 3 - 'Name','First','Last', ""
Here is what I tried, using the stream API and Java 11 Predicate.not API:
Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty).or(entry -> entry.equals("Name")))
.collect(Collectors.toList());
I would expect the entries "Name" and "" to be removed from myStringArray, what am I missing?
Another possibility:
var newList = new ArrayList<>(Arrays.asList(myStringArray));
newList.removeAll(List.of("", "Name"));
Or, if you know that "Name" is always the first entry and "" is always the last entry, you could do this, which has better performance as it doesn't take any copies of anything:
var newList = Arrays.asList(myStringArray).subList(1, myStringArray.length - 1)
My question formation may have been poor, sorry about that and here's what I was looking for and it produces the desired result that I need -
Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty))
.filter(Predicate.not(entry -> entry.equals("Name")))
.collect(Collectors.toList());
Another way to do this without doing two filter calls can be:
Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty).and(entry -> !entry.equals("Name")))
.collect(Collectors.toList())
I think the problem you have, is that you are not taking resulting list. The thing is, the items are not removed from the array, but new list is created with items without removed items.
so just do:
var newList = Arrays.asList(myStringArray).stream()
.filter(Predicate.not(String::isEmpty)).filter(Predicate.not(entry -> entry.equals("Name")))
.collect(Collectors.toList());```

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 generate sequence of numbers for every task in spark

I am using below code for mapping some data in spark. I need a unique sequential number to be generated for every task while mapping it to pair rdd. I tried using the accumulators. But I got to know from the exceptions that retrieving the value form an accumulator is not possible inside the task. Please help me on this as I am very new to spark and have no idea about the solution.
Accumulator<Integer> uniqueIdAccumulator = context.getJavaSparkContext().accumulator(0, "uniqueId");
JavaPairRDD<String, String> rdd1 = javaPairRdd.mapToPair(f-> {
uniqueIdAccumulator.add(1);
return new Tuple2<String,String>(f._1, this.getMessageString(f._2, null,uniqueIdAccumulator.value()));
});
JavaPairRDD rdd1 = javaPairRdd.zipWithIndex().mapToPair(f-> {
return new Tuple2(f._1._1,this.getMessageString(f._1._2, null, f._2));
});
There is no need of accumulator here. ZipWithIndex helped getting the solution. ZipWIthIndex returns a RDD with the existing tuple and Long index number. I used the index number to generate the unique sequence number.

ADOBE CQ5 JCR - How to orderby/sorting query builder result using node's property

basically below is the java coding part, which the result will then be populated to a .csv file. However, I dont seem get the ordering part right (last line in below snippet).
Map<String, String> map = new HashMap<String, String>();
map.put("path", "/etc/crx-db/form-data/career");
map.put("type", "nt:unstructured");
map.put("p.limit", "-1");
map.put("daterange.property", "created");
map.put("daterange.lowerBound", from);
map.put("daterange.lowerOperation", ">=");
map.put("daterange.upperOperation", "<=");
map.put("daterange.upperBound", to);
map.put("orderby", "created"); //<--here
Providing that in crx repositry (/etc/crx-db/form-data/career), I have nodes: data1, data2, data3...
Then for each node, there is one property - Name: created | Type: Date | Value: 2014-01-28T23:21:15.029+08:00 (eg)
However my result in .csv is incorrect like (row 1 to 5):
2014-01-28T23:21:15.029+08:00
2014-01-28T23:48:12.219+08:00
2014-02-10T18:44:38.914+08:00 <-- unsorted
2014-02-10T18:43:32.426+08:00 <-- unsorted
2014-02-10T18:46:53.319+08:00
Pretty sure my code wasn't running. Any idea on how can I tweak my java code to make the sorting happen? As in returning sorted data1, data2, data3... based on the property created. Thanks.
You were almost there. It can be done as follows.
map.put("orderby", "#created");
map.put("orderby.sort", "desc"); // in case you want it descending
In case you need to check property within a child node, you can provide the relative path to that for the orderby value. For eg., if you are searching for dam:Asset and want to order them based on the jcr:lastModified property of its metadata, then your query would be something similar to this.
map.put("path", "/content/dam/geometrixx");
map.put("type", "dam:Asset");
map.put("orderby","#jcr:content/metadata/jcr:lastModified");
For further learning refer this

retrieving the values from the nested hashmap

I have a XML file with many copies of table node structure as below:
<databasetable TblID=”123” TblName=”Department1_mailbox”>
<SelectColumns>
<Slno>dept1_slno</Slno>
<To>dept1_to</To>
<From>dept1_from</From>
<Subject>dept1_sub</Subject>
<Body>dept1_body</Body>
<BCC>dept1_BCC</BCC>
<CC>dept1_CC</CC>
</SelectColumns>
<WhereCondition>MailSentStatus=’New’</WhereCondition>
<UpdateSuccess>
<MailSentStatus>’Yes’</MailSentStatus>
<MailSentFailedReason>’Mail Sent Successfully’</MailSentFailedReason>
</UpdateSuccess>
<UpdateFailure>
<MailSentStatus>’No’</MailSentStatus>
<MailSentFailedReason>’Mail Sending Failed ’</MailSentFailedReason>
</ UpdateFailure>
</databasetable>
As it is not an efficient manner to traverse the file for each time to fetch the details of each node for the queries in the program, I used the nested hashmap concept to store the details while traversing the XML file for the first time. The structure I used is as below:
MapMaster
Key Value
123 MapDetails
Key Value
TblName Department1_mailbox
SelectColumns mapSelect
Key Value
Slno dept1_slno
To dept1_to
From dept1_from
Subject dept1_sub
Body dept1_body
BCC dept1_BCC
CC dept1_CC
WhereCondition MailSentStatus=’New’
UpdateSuccess mapUS
MailSentStatus ’Yes’
MailSentFailedReason ’Mail Sent Successfully’
UpdateFailure mapUF
MailSentStatus ’No’
MailSentFailedReason ’Mail Sending Failed’
But the problem I’m facing now is regarding retrieving the Value part using the nested Keys. For example,
If I need the value of Slno Key, I have to specify TblID, SelectColumns, Slno in nested form like:
Stirng Slno = ((HashMap)((HashMap)mapMaster.get(“123”))mapDetails.get(“SelectColumns”))mapSelect.get(“Slno”);
This is unconvinent to use in a program. Please suggest a solution but don’t tell that iterators are available. As I’ve to fetch the individual value from the map according to the need of my program.
EDIT:my program has to fetch the IDs of the department for which there is privilege to send mails and then these IDs are compared with the IDs in XML file. Only information of those IDs are fetched from XML which returned true in comparison. This is all my program. Please help.
Thanks in advance,
Vishu
Never cast to specific Map implementation. Better use casting to Map interface, i.e.
((Map)one.get("foo")).get("bar")
Do not use casting in your case. You can define collection using generics, so compiler will do work for you:
Map<String, Map> one = new HashMap<String, Map>();
Map<String, Integer> two = new HashMap<String, Integer>();
Now your can say:
int n = one.get("foo").get("bar");
No casting, no problems.
But the better solution is not to use nested tables at all. Create your custom classes like SelectColumns, WhereCondition etc. Each class should have appropriate private fields, getters and setters. Now parse your XML creating instance of these classes. And then use getters to traverse the data structure.
BTW if you wish to use JAXB you do not have to do almost anything! Something like the following:
Unmarshaller u = JAXBContext.newInstance(SelectColumns.class, WhereCondition.class).createUnmarshaller();
SelectColumns[] columns = (SelectColumns[])u.unmarshal(in);
One approach to take would be to generate fully qualified keys that contain the XML path to the element or attribute. These keys would be unique, stored in a single hashmap and get you to the element quickly.
Your code would simply have to generate a unique textual representation of the path and store and retrieve the xml element based on the key.

Categories