I have a nested map, something like this:
map.get("employee").get("address").remove("city")
Is there a way to remove the city entry using a key like "employee.address.city"? So I am looking for something like MapUtil.remove(map,"employee.address.city")
Java 8 library Dynamics can do this, it wraps a nested map/collection (amongst other types) structure and allows null-safe reasoning without static typing.
Dynamic.from(map).get("employee").get("address").asMap().remove("city");
We wrap the map to obtain our Dynamic instance, #get now returns other Dynamic instances representing the child, or absence of that child. As such this is null-safe.
For convenience we can also use #dget to split a get into many, and perhaps #maybe to handle the cases where the employee or address don't exist without exception:
Dynamic.from(map).dget("employee.address")
.maybe().asMap()
.ifPresent(address -> address.remove("city"));
See more examples https://github.com/alexheretic/dynamics
Not natively, no, though you could write yourself a method to parse your extended map key using String.split("\\."), like this:
public void nestedRemove(Map map, String keyToRemove)
{
String string = "employee.address.city";
String[] keys = string.split("\\.");
Map subMap = null;
for(int i = 0; i < keys.length -1; i++)
{
subMap = subMap.get(keys[i]);
}
subMap.remove(keys[i]);
}
You could write your own method to do this, although you'd be likely to have to resort to a fair amount of casting. You'd probably just split on dots, then keep calling get (and remembering the result for the next step) until you got to the last part, at which point you'd call remove instead... remembering to check for a null return from get at every step.
I don't know of anything built into a third party library to do this - which isn't to say it's nowhere, of course.
Related
I have a map of strings that all need to be modified by one of several functions based on some conditions.
My problem is that once I return the map, I need someway to identify which function was used on that specific string. My current idea is to add an identfier at the end of each string so I can check.
Ex. In the case the function "HPV" was used : mystring = mystring + "HPV"
Then on the return end, I can check the end of the string and know which function was used.
Is this an appropriate solution or is there a more efficient way that does not involve checking and modifying every single string?
You should probably use an object that can return both the actual String and the identifier of the function that did the work on it.
If the functions that will do the work are all known at compile-time, they can be identified by an enum, otherwise just another String that holds their ID.
Here is a simple suggestion on how to do that:
enum StringModifier {
HPV, OTHER
}
record ModifiedString(
String string,
StringModifier modifier
) {}
main(String[] args) {
Map<String, String> originalMap = ...
Map<String, ModifiedString> modifications = transform(originalMap, ...)
}
This avoids allocating new Strings and "dirty-ing" them, which can give you trouble later to clean them up as you probably want to make sure you know what the actual result String should look like.
I know similar questions have been asked already, but every time the answers revolve around "use a Map instead".
In my case, I HAVE to use a List. More precisely, I can use other data structures for treatment, but the information will be stored ultimately in the form of a List.
Here is the situation : I have an object, which I will call Sequence, containing a List of objects I will call Phase.
Among other properties, the Phase object is given a UUID through ObjectId
During a given treatment, I have to replace an existing Phase inside the List<Phase> contained in Sequence by another Phase. The input for this are the replacement Phase object and a String value of the ObjectId of the Phase to replace
I was hoping to be able to do something like this using Java8 :
public void replacePhase(Sequence sequence, Phase replacementPhase, String idPhaseToBeReplaced) {
List<Phase> phaseList = sequence.getPhaseslist();
Phase phaseToBeReplaced = phaseList.stream().filter(p -> p.getId().toString().equalsIgnoreCase(idPhaseToBeReplaced)).findFirst().orElse(null);
if (phaseToBeReplaced != null) {
phaseToBeReplaced = replacementPhase;
}
And voilà, the List<Phase> would be updated.
I know something like this will work :
public void replacePhase(Sequence sequence, Phase replacementPhase, String idPhaseToBeReplaced) {
List<Phase> phaseList = sequence.getPhaseslist();
Phase phaseToBeReplaced = phaseList.stream().filter(p -> p.getId().toString().equalsIgnoreCase(idPhaseToBeReplaced)).findFirst().orElse(null);
if (phaseToBeReplaced != null) {
int i = phaseList.indexOf(phaseToBeReplaced );
phaseList.set(i, replacementPhase);
phaseToBeReplaced = replacementPhase;
}
But it doesn't seem more efficient that using a for loop on phaseList with a break when finding a Phase with the desired UUID.
So my question is : is there a way, using List data structure, to find an object based on a (in this case, unique) property and then replace said object inside the List by another (of the same type), preserving order? Preferably without iterating over the whole List and using Java8 functionnalities?
In order to make your replace functionality work in short-circuit fashion, use ListIterator:
ListIterator<Phase> iterator = phaseList.listIterator();
while(iterator.hasNext()){
Phase phase = iterator.next();
if(phase.getId().toString().equalsIgnoreCase(idPhaseToBeReplaced)){
iterator.set(replacementPhase);
break;
}
}
In case the id is not unique, just remove the break. Or use List::replaceAll.
You seem to be looking for List#replaceAll such as :
sequence.getPhasesList()
.replaceAll(phase -> phase.getId().toString()
.equalsIgnoreCase(idPhaseToBeReplaced) ? replacementPhase : phase);
If you keep the list sorted you can find the item using binary search, that would be faster than iterating the list.
Collections.binarySearch
If you need to keep it sorted by insertion order, use a LinkedHashMap
I've got loads of the following to implement.
validateParameter(field_name, field_type, field_validationMessage, visibleBoolean);
Instead of having 50-60 of these in a row, is there some form of nested hashmap/4d array I can use to build it up and loop through them?
Whats the best approach for doing something like that?
Thanks!
EDIT: Was 4 items.
What you could do is create a new Class that holds three values. (The type, the boolean, and name, or the fourth value (you didn't list it)). Then, when creating the HashMap, all you have to do is call the method to get your three values. It may seem like more work, but all you would have to do is create a simple loop to go through all of the values you need. Since I don't know exactly what it is that you're trying to do, all I can do is provide an example of what I'm trying to do. Hope it applies to your problem.
Anyways, creating the Class to hold the three(or four) values you need.
For example,
Class Fields{
String field_name;
Integer field_type;
Boolean validationMessageVisible;
Fields(String name, Integer type, Boolean mv) {
// this.field_name = name;
this.field_type = type;
this.validationMessageVisible = mv;
}
Then put them in a HashMap somewhat like this:
HashMap map = new HashMap<String, Triple>();
map.put(LOCAL STRING FOR NAME OF FIELD, new Field(new Integer(YOUR INTEGER),new Boolean(YOUR BOOLEAN)));
NOTE: This is only going to work as long as these three or four values can all be stored together. For example if you need all of the values to be stored separately for whatever reason it may be, then this won't work. Only if they can be grouped together without it affecting the function of the program, that this will work.
This was a quick brainstorm. Not sure if it will work, but think along these lines and I believe it should work out for you.
You may have to make a few edits, but this should get you in the right direction
P.S. Sorry for it being so wordy, just tried to get as many details out as possible.
The other answer is close but you don't need a key in this case.
Just define a class to contain your three fields. Create a List or array of that class. Loop over the list or array calling the method for each combination.
The approach I'd use is to create a POJO (or some POJOs) to store the values as attributes and validate attribute by attribute.
Since many times you're going to have the same validation per attribute type (e.g. dates and numbers can be validated by range, strings can be validated to ensure they´re not null or empty, etc), you could just iterate on these attributes using reflection (or even better, using annotations).
If you need to validate on the POJO level, you can still reuse these attribute-level validators via composition, while you add more specific validations are you´re going up in the abstraction level (going up means basic attributes -> pojos -> pojos that contain other pojos -> etc).
Passing several basic types as parameters of the same method is not good because the parameters themselves don't tell much and you can easily exchange two parameters of the same type by accident in the method call.
I deal a lot with the pre-generics like Maps with Strings as the keys. They are mapping the keys to one of the following types of values:
Another Map
A List
Primitives wrappers
You can access the collection content using either XPath or queries like that:
myMap/FIRST_LIST[2]/SECOND_LIST[1]/MY_MAP/MY_PRIMITIVE
What I am looking for is a library that would allow me to apply a visitor function to the multiple elements of a collection. The basic functionality could look like that
MyMapBrowser browser = new MyMapBrowser(myMap);
browser.applyVisitor("FIRST_LIST[*]/SECOND_LIST[*]/MY_MAP/MY_PRIMITIVE",
new AbstractVisitor<String>() {
visit(String s) {
// do something with the strings
}
});
It would be also wonderful to have a possibility to first register multiple visitors for various levels of collection and then start the visiting iteration. It could look like this:
browser.registerVisitor(SECOND_LIST, new AbstractVisitor<MyList> { ... )
browser.doVisiting("FIRST_LIST[*]/SECOND_LIST[*]/MY_MAP/MY_PRIMITIVE");
In fact I've already started implementing a browser like that but I can't get rid of an impression that I'm reinventing the wheel.
Have you looked into JXPath? It lets you use XPath expressions to query and manipulate Java object graphs. The JXPathContext class lets you iterate over the values of selected nodes if you just want to extract the string values, or you can use the selectNodes method to get JDOM wrappers.
For instance, I think your example query would look something like:
// untested
JXPathContext context = JXPathContext.newContext(myMap);
Iterator iter = context.iterate("FIRST_LIST/SECOND_LIST/MY_MAP/MY_PRIMITIVE");
while (iter.hasNext()) {
String str = (String) iter.next();
// do something with strings
}
Unfortunately I haven't actually worked with JXPath (though I've also tried implementing an XPath-like traverser before too), but apparently you can also configure it to automatically create objects for a particular path. I didn't see any visitor functionality, but the iterate, getValue, and setValue should be able to accomplish the same thing. You could also rig up a simple wrapper class to run the query, iterate through the nodes, and pass the values to your own visitor interface. Something like:
public class JXPathVisitBrowser {
private JXPathContext context;
public JXPathVisitBrowser(Object object) {
context = JXPathContext.newContext(object);
}
public <T> void applyVisitor(String query, AbstractVisitor<T> visitor) {
Iterator iter = context.iterate(query);
while (iter.hasNext())
visitor.visit((T) iter.next());
}
}
There's a pretty detailed JXPath user guide too.
Take a look on LambdaJ. I think this is what you are looking for.
I want to convert user input that comes as Map<String, String[]> to objects in Java. More specically I want to convert the params of a HttpServletRequest to the fields of an arbitrary domain object.
I'd like to have something like this:
Domain d = Converter.convert(params, new Domain());
If there is more than one element in the string array, which is the value of a map entry, it should be converted to a list or array. Maybe the locale should be considered for date and currency conversion. And a list of conversion errors would be nice.
Is there a library with such a converter?
Would you call it "converter"? I think it is often called "data binding", but that is the wrong term in my opionion, since it is related to binding model values to GUI elements, what is a slightly different thing - isn't it?
If your web framework does not support this functionality have a look at
http://commons.apache.org/beanutils/ ,espeically the beanutils package which has classes with similar purposes (maybe exactly the same) that you want.
You may also consider switching to a more mature framework ;-)
Don't use this plain code as it is only an example. You should add some pretty exception handling and a loop through a map. But generally the idea is like this:
void putValue(String name, String value, Object object) throws Exception {
String setterName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
Method m = object.getClass().getMethod(setterName, String.class);
if (m!=null) {
m.invoke(object, value);
}
}
This code, given a parameter name 'name' will try to find a method setName(String name) and call it with the given value.