Update the content of Properties instance - java

I have an instance of Properties, named props. The key-value contents are as follows:
"a" : "apple"
"c" : "orange"
"b.1" : "tea"
"b.2" : "coffee"
"b.3" : "coke"
...
(Each key is unique.)
What I want to achieve is:
I am only interested in keys b.<number>, I need b.1 has value water.
if there is a value water but is not with key b.1, instead, with key b.<x>, then, I swap the value of b.1 & b.<x>.
If there isn't a value water, I increase the number part of key b.<number> by 1, after which I insert "b.1" : "water" in the Properties instance.
I started to implement it with this code:
// initialize a HashMap
Map<String, String> propMap = new HashMap<String, String>();
// check what are the property key-values
Set<Object> keySet = props.keySet();
for (Object key : keySet) {
String keyStr = (String) key;
String valueStr = props.getProperty(key);
if (keyStr.startsWith("b.")) {
// if it is not value "water"
if (!valueStr.equals("water")) {
// I get lost...
}
}
}
I am not sure how to implement this in an efficient way without looping through the properties multiple times...

I don't readily see a way to do this without iterating twice (or in the case below, copying to a new Properties object), but the code below will work. Also, I create another Properties object only when water is not found, so it may not be terrible depending on your use case.
private static Properties setUpProperties() {
Properties props = new Properties();
props.setProperty("a", "apple");
props.setProperty("c", "orange");
props.setProperty("b.1", "tea");
props.setProperty("b.2", "coffee");
props.setProperty("b.3", "coke");
return props;
}
#Test
public void testProperties() {
#SuppressWarnings("unchecked")
Map<String, String> sortedMap = new TreeMap(updateContents()); //just for logging
System.out.print("Properties=" + sortedMap);
}
public static Properties updateContents() {
// initialize a HashMap
Properties props = setUpProperties();
#SuppressWarnings("unchecked")
Map<String, String> sortedMap = new TreeMap(props); //just for logging
System.out.print("Properties="+sortedMap+"\n");
// check what are the property key-values
boolean foundWater = false;
for (String key : props.stringPropertyNames()) {
if (key.startsWith("b.")) { //only b keys
String value = props.getProperty(key);
if ("water".equals(value)) {
foundWater = true;
if ("b.1".equals(key)) {
return props;
}
else {
//swap b.1 value with b.x value
int digit = getDigit(key);
props.setProperty("b." + digit, props.getProperty("b.1"));
props.setProperty("b.1", "water");
}
}
}
}
if (foundWater) {
return props;
}
else {
Properties propertiesCopy = new Properties(); //avoid a ConcurrentModificationException
propertiesCopy.putAll(props);
for (String key : propertiesCopy.stringPropertyNames()) {
//increment all other b-values by one
if (key.startsWith("b.")) {
int digit = getDigit(key);
int incremented = digit + 1;
propertiesCopy.setProperty("b." + incremented, propertiesCopy.getProperty(key));
}
}
propertiesCopy.setProperty("b.1", "water");
return propertiesCopy;
}
}
/**
* Returns the digit given a key from a Properties object (this is x)
*/
private static int getDigit(String key) {
String digit = key.substring(key.lastIndexOf(".") + 1); //use period as delimiter
return Integer.valueOf(digit);
}
You could also put in equalsIgnoreCase checks instead.

Related

finding a specific value in a hashmap

Is there a code for finding a specific value in a hashmap?
I want to use a for loop to convert values in a hashmap into an int.
for (int i = 0; i < items; i++) {
cost = Integer.parseInt(myHashmap);
}
can I even use .parseInt on a hashmap or is there another way to convert a place in a hashmap into a int?
Like String[3] is there a code to find a specific place in a hashmap?
To iterate over all values of a map, use the values method:
Map<Long, String> map = ...;
for (final String value = map.values()) {
System.out.println(value);
}
To find a specific value, iterate all values, check against your predicate and return if found:
String findValue(final Map<Long, String> map, final Predicate<String> condition) {
for (final String value = map.values()) {
if (condition.test(value)) {
return value;
}
}
return null;
}
To find the key for a given value, iterate the entry set of the map:
Long findKey(final Map<Long, String> map, final String value) {
for (final Map.Entry<Long, String> entry = map.entrySet()) {
if (Objects.equals(entry.getValue(), value)) {
return entry.getKey();
}
}
return null;
}
Of course, once you have a value (or a key), you can use it any way you like. That includes passing it as argument to Integer.parseInt.
myHashmap.values() will return all the values of the Map. Integer.parseInt(value) parses the String argument as a signed decimal integer object.
public static void main(String[] args) {
Map<String, String> myHashmap = new HashMap<>();
myHashmap.put("A", "10");
myHashmap.put("B", "20");
myHashmap.put("C", "30");
myHashmap.values().forEach(value -> {
System.out.println(Integer.parseInt(value));
// Rest of the logic
});
}

Hashmap overwrites values. How to add multiple of the same key?

I know hashMap overwrites the kay, but I really need the same key to be provided for another value. What is also the issue is that in the postRequest further down, it needs to be set as a Map value.
So how can the below be fixed so that the body contains all the field and their values below as displayed in the table?
So we can't have field3 = tree, cone, it has to be field 3 = tree, field 3 = cone or the service will fail.
Example step:
|field |value |
|----------|--------------------------------------------|
|field1 |shop |
|field2 |apple |
|field3 |tree |
|field3 |cone |
#Step("Example step: <table>")
public void exampleStep(Table table) {
Map<String, Object> body = new HashMap<>();
table.getTableRows().forEach(row -> {
String value = row.getCell(VALUE);
String field = row.getCell(FIELD);
body.put(field, value);
});
final String url = String.format("%s/service/%s", System.getenv(ENDPOINT), service);
new DBrequest(dataStore, url, HttpMethod.POST).postRequest(body);
If you have a Map<String, List<String>> for example, you have to check if keys are present when you are inputting values, see this:
#Step("Example step: <table>")
public void exampleStep(Table table) {
table.getTableRows().forEach(row -> {
String value = row.getCell(VALUE);
String field = row.getCell(FIELD);
// you have to check if the key is already present
if (body.containsKey(field)) {
// if it is, you can simply add the new value to the present ones
body.get(field).add(value);
} else {
// otherwise you have to create a new list
List<String> values = new ArrayList<>();
// add the value to it
values.add(value);
// and then add the list of values along with the key to the map
body.put(field, values);
}
});
}
You can iterate such a Map in several ways, one is this:
for (Entry<String, List<String>> entry : body.entrySet()) {
// print the key first
System.out.println(entry.getKey() + ":");
// then iterate the value (which is a list)
for (String value : entry.getValue()) {
// and print each value of that list
System.out.println("\t" + value);
}
};
}
Please note:
This is a simple example without any content and it doesn't handle any casting from Object.

Retrieve key from HashMap

How to retrieve index of a map using key value?
I have a map with string as key and int as value.
I will pass map and key value to a method,in that method based on the index of the passed key value it will return either true or false. I need this util method for my application.
package sample;
import java.util.HashMap;
import java.util.Map;
public class MAp {
public static void main(String args[]) {
Map<String, Integer> sampleMap = new HashMap<String, Integer>();
sampleMap.put("ABC", 12);
sampleMap.put("DEF", 13);
boolean flag = canAllocate("ABC", sampleMap);
}
private static boolean canAllocate(String string, Map<String, Integer> sampleMap) {
if (sampleMap.containsKey("ABC")) {
int index = 0;
// I need to get index of "ABC" in map;
if (index == 0) {
return true;
}
}
return false;
}
}
I would suggest you try using a LinkedHashMap, which will preserve the order, then do as Mena suggested. Otherwise, the 'order' doesn't mean much.
You could just iterate the keySet and increment an int.
index i = 0;
for (String key: sampleMap.keySet()) {
if (key.equals(myString)) {
return i;
}
else {
i++;
}
}
return -1;
To be noted, there is no indexing as such in the key set, so the whole functionality seems to have little value.
" // I need to get index of "ABC" in map "
It has no sense to do that, "ABC" itself is a sort of index ine the MAP.
Key -> Map
Index -> Array/List

Why do I get the wrong HashCode from string?

I have this structure:
private HashMap<Integer,HashMap<Object,Integer>> commandList= new HashMap<>();
populated this way:
{1={1=2, 2=3, 3=4, -999=-999, -998=-998}}
from this code:
if ((msgTypeTemp=commandList.get(this.msgType).get(msgContent))==null) {
Object s= "1";
System.out.println("Class of s: "+s.getClass().getSimpleName()+"\nClass of msgContent: "+msgContent.getClass().getSimpleName());
System.out.println("msgMap:\n"+msgMap);
System.out.println("commandList:\n"+commandList);
System.out.println(s.hashCode());
System.out.println(msgContent.hashCode());
System.out.println(commandList.get(this.msgType).get(s));
this.msgType=JSockOS_UndefinedMsg.MSG_CODE;
specialMsg=true;
} else {
this.msgType=msgTypeTemp;
if (specialMsgType(this.msgType)){
specialMsg=true;
}
}
My HashMap is generic type <String,Integer>
However, whenever I call the get method on msgContent, it comes out that instead of the hashcode of "1", it was a hashcode which until that moment was set to 0, and which then changed after the get method call.
This happens only for calls that use "msgContent" parameter...
If I use this: System.out.println(commandList.get(this.msgType).get(s));
It returns "2" as expected...
Look also this image, it may help.
msgContent gets changed before the above code in this way:
it was first: 2.1.
then it gets: 1.
remaining a string.
msgContent=msgContent.toString().split(Pattern.quote("."))[1];
do(msgContent); // a methods which implements the code showed before.
//msgContent is a parameter, --> public void do(Object msgContent)
[EDIT]:
PROBLEM FOUND: msgContent is 495 chars... will fix its changes and update!
Even though String is immutable, the value of hashCode is computed lazily for performance reasons, as shown here:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
As far as your actual problem is, are you entirely certain that your keys are String? The type you've provided there is <Object, Integer>, not <String, Integer>.
My test case works fine as shown here (this prints elseSide):
public static void main(String... args) {
HashMap<Integer, HashMap<Object, Integer>> map = new HashMap<>();
HashMap<Object, Integer> innerMap = new HashMap<>();
innerMap.put("1", 2);
innerMap.put("2", 3);
innerMap.put("-999",-999);
innerMap.put("-998",-998);
map.put(1, innerMap);
int msgType = 1;
String msgContent = "2.1";
msgContent = msgContent.toString().split(Pattern.quote("."))[1];
System.out.println(map);
if(map.get(msgType).get(msgContent) == null) {
System.out.println("ifSide");
} else {
System.out.println("elseSide");
}
}
I think you should try adding the following debugging statements:
HashMap<Object, Integer> innerMap = commandList.get(this.msgType);
for(Map.Entry<Object, Integer> entry : innerMap.entrySet()) {
System.out.println("KeyClass: " + entry.getKey().getClass() +
"\tKeyValue:" + entry.getKey());
// This will make sure the string doesn't have any unprintable characters
if(entry.getKey() instanceof String) {
String key = (String) entry.getKey();
System.out.println("Key Length: " + key.getLength());
}
}
I don't think your key in your inner map is actually a String, or perhaps the String somehow has unprintable characters. A hash of 630719471 is much too high for a one character String. It's also possible that msgContent has unprintable characters as well.

hasmap return key and value methods give incorrect output

I want to create methods which return the amount of same first names and last names, but when i try to test and compile code i get as output 1 , 1 , and this is not true. because there is 10 same names and 10 same last names.
public class Solution
{
public static void main(String[] args)
{
HashMap<String, String> map = createMap();
System.out.println(getCountTheSameFirstName(map, "test"));
System.out.println(getCountTheSameLastName(map, "test"));
}
public static HashMap<String, String> createMap()
{
HashMap<String, String> odin = new HashMap<String, String>();
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
odin.put("test","test");
return odin;
}
public static int getCountTheSameFirstName(HashMap<String, String> map, String name)
{
int count = 0;
for(Map.Entry<String, String> lol : map.entrySet()){
String value = lol.getValue();
if(name.equals(value)){
count++;
}
}
return count;
}
public static int getCountTheSameLastName(HashMap<String, String> map, String familiy)
{
int count=0;
for (Map.Entry<String,String> pair : map.entrySet())
{
String key = pair.getKey();
if (familiy.equals(key))
{
count++;
}
}
return count;
}
}
Please consult the HashMap-API, it is correct by definition: "Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced." (http://docs.oracle.com/javase/6/docs/api/java/util/HashMap.html#put(K, V))
Sorry!! if you are not use duplicate key then you have to have get the output 10 & 0
Your code: Just I have changed the key and got the output 10 & 0:
public class Solution
{
public static void main(String[] args)
{
HashMap<String, String> map = createMap();
System.out.println(getCountTheSameFirstName(map, "test"));
System.out.println(getCountTheSameLastName(map, "test"));
}
public static HashMap<String, String> createMap()
{
HashMap<String, String> odin = new HashMap<String, String>();
odin.put("0","test");
odin.put("1","test");
odin.put("2","test");
odin.put("3","test");
odin.put("4","test");
odin.put("5","test");
odin.put("6","test");
odin.put("7","test");
odin.put("8","test");
odin.put("9","test");
return odin;
}
public static int getCountTheSameFirstName(HashMap<String, String> map, String name)
{
int count = 0;
for(Map.Entry<String, String> lol : map.entrySet()){
String value = lol.getValue();
if(name.equals(value)){
count++;
}
}
return count;
}
public static int getCountTheSameLastName(HashMap<String, String> map, String familiy)
{
int count=0;
for (Map.Entry<String,String> pair : map.entrySet())
{
String key = pair.getKey();
if (familiy.equals(key))
{
count++;
}
}
return count;
}
}
You are inserting the same key 10 times. The first put works, but each subsequent put replaces the old key/value mapping with the same mapping. The end result is that there's only one key/value pair in the Map, so that's why you get 1 as output.
In short: Your method works as HashMap is designed - you force put to HashMap with same key and first time add value to map, and any other time you just change value of this element because it has same key.
Description:
You have this situation - You are created HashMap like that:
HashMap<String, String> odin = new HashMap<String, String>();
There is first string key and second string value. When you adding value with line:
odin.put("test","test");
You are set value test for key test.
If you repeat that, you will change old element with key test with new element with key test
This results is that entered value is replaced.
Instead of this, you have to put in HashMap something else (array for example) with unique key. In this case you can have 10 inputs with same values.
Here is example of this HashMap:
HashMap<String, String[]> odin = new HashMap<String, String[]>();
In that case you have to provide string key and array of strings which contains values (first names and last names from your question).

Categories