Change part of the value in a HashMap using java - java

I have a HashMap with String as the key type and String[] as value type.
I want to be able to change part of the value (a String array).
I am storing files' contents using this HashMap by saving the file name as the key and its contents as the value (String[]).
I've succeeded in collecting all the data for this HashMap. I want the value
to be displayed in this way:
Key: alert
Value:
0-=Rule_Name,Configuration_Set_ID,Alert_UID,Headline,Create_DateTime
1-f5_high_compression_profile,,211,61b6cc42-0b32-4bd9-a3be-a98d7144ca85,Compression profile gzip level too high,1565003688537
2-f5_automap_enabled,407,0b380e7d-22f9-40c2-8277-3a5ed2ea7116,Automap enabled,1565003696956
I want to replace value of epochtime in the string to Date with this convention yyyy/MM/dd HHmmss for each record (epoch time may be different in the file).
public void createHashMapWithAlertCSVContent() throws Exception {
for(String item: lstServer) {
String[] contentCSVStr=
CmdHelper.Remote.File.cat(SERVER,INDENI_INSIGHT_PATH +
"/"+item).split("\n");
mapServer.put(FileUtil.removeExtension(item), contentCSVStr);
}
if(mapServer.containsKey("job")) {
mapServer.remove("job");
Assert.assertEquals(mapServer.size()-1, lstServer.size());
} else {
Assert.assertEquals(mapServer.size(), lstServer.size());
}
mapServer.entrySet().forEach(entry-> {
System.out.println(entry.getKey() + " " +
entry.getValue());
});
}
What I expected to happen was any entry of epoch time in the array of string would be replaced to yyyy/MM/dd HHmmss convention.
I have this string f5_high_compression_profile,,211,61b6cc42-0b32-4bd9-a3be-a98d7144ca85,Compression profile gzip level too high,1565003688537.
I want to change 1565003688537 to look like the yyyy/MM/dd HHmmss convention.
1565003688537 may not be the same value when I read the content of the CSV, so it has to be able to handle that.
I want to change each entry of ecpoh time into date format value.

You can just read the value by map.get(key) then edit it and the put it again with map.put(key, value).
If the value is of a muatable type, eg. String[] then you can just make modifications directly on this object, because the map is referencig to this object and not holding a copy.
eg.
String[] value = map.get(key);
value[0] = "new String";
If you want to change the size of the String[] then you need to create new list and put it under same key to replace the previous value, or you can change the type to use List instaed of String[] so it will be easier to modify it.

Related

String value from properties file

I have a properties (cant change this file) and it looks like:
aaa.bbb.ccc.first=my first value
aaa.bbb.ccc.second=my second value
aaa.bbb.ccc.third=my third value
If I need any value in java classes I use i18n.getText("aaa.bbb.ccc.first") but it works only for single value.
Problem is because I dont know:
-value's names
-how many values are in aaa.bbb.ccc.~
How is it possible to get list of value aaa.bbb.ccc~?
You could use a MapFilter. Use the MapFilter(Properties p, String prefix) constructor.
public void test() {
Properties props = new Properties();
props.put("aaa.bbb.ccc.first", "my first value");
props.put("aaa.bbb.ccc.second", "my second value");
props.put("aaa.bbb.ccc.third", "my third value");
props.put("Other.props", "others");
MapFilter<String> filtered = new MapFilter(props, "aaa.bbb.ccc.");
for (Map.Entry<String, String> e : filtered.entrySet()) {
System.out.println("Key: " + e.getKey() + " Value: " + e.getValue());
}
System.out.println(filtered);
}
Hash maps are not meant for the kind of lookup you want to do: Tries and radix trees are. There is an implementation of the Patricia trie data structure (i.e., binary radix trees) in Apache Commons Collections: Just create a trie from your Map<String, Whatever> (you have a nice constructor at the purpose) and with prefixMap("aaa.bbb.ccc") you obtain the submap of all the entries whose key have that prefix.
Properties has a method propertyNames(). You can use that to get all the keys then do whatever you want from there.

Compare data of two or more maps

I am stuck with the below requirement and not sure how can I proceed with it:
I have a function like:
public void compareExcel(Map<Object,List<HashMap>>) compareMaps){}
This function will take a map as an input parameter. This map will contain the sheet name vs Sheet values(Column name - column values) mapping.
Basically the function input parameters will be like:
<Excel1,(scenario:10)
(timing: 20)
Excel2,(scenario:30)
(timing: 40)
Excel3,(scenario:50)
(timing: 60)
>
Here my excel1 having two columns(scenario and timings) and having values as 10 and 20 respectively.
In the result, I will be needing the comparison like:
Map>
<scenario, <excel1,10>
<excel2,30>
<excel3,50>
timing, <excel1,20>
<excel2,40>
<excel3,60>
>
Any help will be appreciated.
Create/initialize the details of you output data-structure
LOOP (over the excelName:List pairs in you input)
LOOP (over the List that is the value in the pair)
//Each entry in the list is a map
Get the key-name (e.g. "scenario")
Get the value (e.g. "10")
//You already know the out key (i.e the excelName)
With the three known values, build/add to your output data-structure
On mobile so I can't even check syntax, but...
Map recopilation = new HashMap();
for(Object sheetName : compareMaps.keySet()) {
Map sheet = compareMaps.get(sheetName);
for (Object columnName : sheet.keySet()) {
if (recopilation.get(columnName) == null) {
recopilation.put(columnName, new HashMap());
}
((Map) recopilation.get(columnName)).put(sheetName, sheet.get(columnName));
}
}
Something like that. If it works, you should really throw some generics in there, I didn't mostly to save some typing.

How to read data like those stored in the *.epf file

I want to read data from a .epf file, and the data is like:
/instance/org.eclipse.wb.core/design.palette.flyout.width=192
I think I can use Map<String, String> to store it, but the problem is how to get rid of the =, and then put the left part and right part into the Map?
As jarnbjo mentioned, if it conforms to the property file format, you can read the file using the Properties class.
If you want to store the data in a map, you can use a string function to get the 2 parts of the data:
// Assuming data contains "/instance/org.eclipse.wb.core/design.palette.flyout.width=192"
String[] parts = data.split("=");
// Get the parts
String key = parts[0]; // /instance/org.eclipse.wb.core/design.palette.flyout.width
String value = parts[1]; // 192
// Or just directly use the map
map.put(parts[0], parts[1]);
To test beforehand if the string contains an, just use String#contains().
if (string.contains("=")) {
// Split it.
} else {
throw new IllegalArgumentException("String " + string + " does not contain =");
}
If the files conform to the property file format, you can read them using the Properties class.

Unexplained Java Hashmap Behavior

In the code below, I am creating a hashmap to store objects called Datums, which contain a String (location) and a count. Unfortunately, the code is giving very strange behavior.
FileSystem fs = FileSystem.get(new Configuration());
Random r = new Random();
FSDataOutputStream fsdos = fs.create(new Path("error/" + r.nextInt(1000000)));
HashMap<String, Datum> datums = new HashMap<String, Datum>();
while (itrtr.hasNext()) {
Datum next = itrtr.next();
synchronized (datums) {
if (!datums.containsKey(next.location)) {
fsdos.writeUTF("INSERTING: " + next + "\n");
datums.put(next.location, next);
} else {
} // skit those that are already indexed
}
}
for (Datum d : datums.values()) {
fsdos.writeUTF("PRINT DATUM VALUES: " + d.toString() + "\n");
}
The hashmap has Strings as keys.
Here is the output I get in the error files (example):
INSERTING: (test.txt,3)
INSERTING: (test2.txt,1)
PRINT DATUM VALUES: (test.txt,3)
PRINT DATUM VALUES: (test.txt,3)
The correct output for the print should be:
INSERTING: (test.txt,3)
INSERTING: (test2.txt,1)
PRINT DATUM VALUES: (test.txt,3)
PRINT DATUM VALUES: (test2.txt,1)
What is happening to the Datum with test2.txt as its location? Why is it getting replaced with test.txt??
Basically, I should never see the same location twice. (that is what the !datums.containsKey is checking for). Unfortunately, I'm getting very strange behavior.
This is on Hadoop, by the way, in a reducer.
I tried putting the synchronized here in case it was running in multiple threads, which, to my knowledge, it isn't. Still, the same thing happens.
According to this answer Hadoop's iterator always returns the same object, instead of creating a new object to return each time around the loop.
So, holding onto references to the object returned by the iterator is not valid and will produce surprising results. You'll need to copy the data to a new object:
while (itrtr.hasNext()) {
Datum next = itrtr.next();
// copy any values from the Datum to a fresh instance
Datum insert = new Datum(next.location, next.value);
if (!datums.containsKey(insert.location)) {
datums.put(insert.location, insert);
}
}
Here is a reference to the Hadoop Reducer documentation which confirms this:
The framework will reuse the key and value objects that are passed
into the reduce, therefore the application should clone the objects
they want to keep a copy of.
it is not problem of the map but of the code
datums.put(next.location, next); inserts as value reference that is later chnaged :)
that is why at the end all values in the map are the same equal to last processed datum in the map

Changing LinkedHashMapValues

Below is data from 2 linkedHashMaps:
valueMap: { y=9.0, c=2.0, m=3.0, x=2.0}
formulaMap: { y=null, ==null, m=null, *=null, x=null, +=null, c=null, -=null, (=null, )=null, /=null}
What I want to do is input the the values from the first map into the corresponding positions in the second map. Both maps take String,Double as parameters.
Here is my attempt so far:
for(Map.Entry<String,Double> entryNumber: valueMap.entrySet()){
double doubleOfValueMap = entryNumber.getValue();
for(String StringFromValueMap: strArray){
for(Map.Entry<String,Double> entryFormula: formulaMap.entrySet()){
String StringFromFormulaMap = entryFormula.toString();
if(StringFromFormulaMap.contains(StringFromValueMap)){
entryFormula.setValue(doubleOfValueMap);
}
}
}
}
The problem with doing this is that it will set all of the values i.e. y,m,x,c to the value of the last double. Iterating through the values won't work either as the values are normally in a different order those in the formulaMap. Ideally what I need is to say is if the string in formulaMap is the same as the string in valueMap, set the value in formulaMap to the same value as in valueMap.
Let me know if you have any ideas as to what I can do?
This is quite simple:
formulaMap.putAll(valueMap);
If your value map contains key which are not contained in formulaMap, and you don't want to alter the original, do:
final Map<String, Double> map = new LinkedHashMap<String, Double>(valueMap);
map.keySet().retainAll(formulaMap.keySet());
formulaMap.putAll(map);
Edit due to comment It appears the problem was not at all what I thought, so here goes:
// The result map
for (final String key: formulaMap.keySet()) {
map.put(formulaMap.get(key), valueMap.get(key));
// Either return the new map, or do:
valueMap.clear();
valueMap.putAll(map);
for(Map.Entry<String,Double> valueFormula: valueMap.entrySet()){
formulaMap.put(valueFormula.getKey(), valueFormula.value());
}

Categories

Resources