BiMap single function to convert values to concatenated string value? - java

Is there something equivalent to get all keys (or inverses) from a bit map and concat each with a special character as a completely new string (without iterating through the map and building it manually?
private static final BiMap<String, String> stuff = HashBiMap.create();
static {
stuff.put("S1", "STUFF_TYPE_1");
stuff.put("S2", "STUFF_TYPE_2");
stuff.put("S3", "STUFF_TYPE_3");
}
// The non-terminal <> is what I'm asking if something like exists either with bimap or some other container?
private static final String concateKeys = <stuff.getAllKeys().assignDelimiter("|").toString();>
Then the Value for concateKeys = "S1|S2|S3"

Assuming this is a Guava BiMap, this is just
Joiner.on('|').join(stuff.keySet());

Maybe you want to take a look at the Joiner class of the Google Guava library.

Related

How should I compare URIs in Java?

I have a service class which gates certain URIs and allows them to bypass certain checks.
To do this, I'm adding a list of allowed URIs in a map with the action allowed, as so:
private static final Map<String, Set<String>> ALLOWED_URIS =
ImmutableMap.<String, Set<String>>builder()
.put("https://myurl.com/foo", ImmutableSet.of("GET"))
.put("https://anotherurl/bar", ImmutableSet.of("GET"))
.put("https://example.com/foo2", ImmutableSet.of("GET"))
.build();
It's not clear to me how I should compare a string URI to this, because URIs can potentially end in / or have query parameters or be case insensitive on domain name etc.
Say the input I receive is https://myurl.com/foo?key=value, the comparison would fail here because there's no key in the map that's equal to it.
private static boolean isAllowed(final String uri, final String action) {
return ALLOWED_URIS.getOrDefault(uri, emptySet()).contains(action);
}
What's the best way to do my comparison? Is there a utility class available for this?

Check 2 strings without case sensitivity or use equalsIgnoreCase method

I have some inputted String String usrInput; that user could import some string once into App without any case-sensitivity policy like: "start","Start","START","end" ,"END" and etc.
And I have a Map that i inserted my strings for example "start" into that and put it into HashMap<String, String> myMap:
Map<String, String> listOfActions = new HashMap<>();
listOfActions.put(myStr, myStr);
Now I want to check listOfActions members to get for example "start" filed in every case model ("start","Start","START") , currently I do like below:
if (listOfActions.containsKey(usrInput.toUpperCase())
|| listOfActions.containsKey(usrInput.toLowerCase())) {
/// some do
}
So I want to know:
1. Is there any way to get String value without case-sensitivity?
I will also add this here I couldn't use equalsIgnoreCase() method for get items from Map because its return Boolean.
2. I have similar problem in switch-case statements to check 2 string equality without case-sensitivity.
You can use
Map<String, String> listOfActions = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Other solutions can be Apache's CaseInsensitiveMap or Spring's LinkedCaseInsensitiveMap.
Please see https://www.baeldung.com/java-map-with-case-insensitive-keys for more details about these solutions.
If you only use inputs as map keys (i.e. you don't need to later reproduce the strings in original casing), I suggest just lowercasing all inputs before inserting them into the map:
Map<String, String> listOfActions = new HashMap<>();
listOfActions.put(myStr.toLowerCase(), myStr);
This will simplify locating the values later on, since you know that all keys are already lowercased, so the lookup becomes easy:
if (listOfActions.containsKey(myStr.toLowerCase())) {
// do something
}
When you create a new instance of HashMap, you can override some of its methods, such as put and containsKey like this:
Map<String, String> map = new HashMap<>() {
#Override
public String put(String key, String value) {
return super.put(key.toLowerCase(), value);
}
#Override
public boolean containsKey(Object key) {
return super.containsKey(key.toString().toLowerCase());
}
};
map.put("START", "doStart");
System.out.println(map); // {start=doStart}
System.out.println(map.containsKey("START")); // true
System.out.println(map.containsKey("Start")); // true
System.out.println(map.containsKey("start")); // true
One thing you can do is make everything upper-case or lower-case, then compare them.
string.toLowerCase().equals("other string");
string.toUpperCase().equals("OTHERSTRING");
This way, whether it is lower-case or upper-case, it will only be compared as one or the other, and acts as though it were case insensitive.

How can I split a String using Splitter.MapSplitter from Guava until a specific key?

I have a String like "key1:value1|prop:id|key3:value3|id:ABC.CDE|key4:value4", how can I split using Splitter.MapSplitter from Guava until id key?
Splitter.MapSplitter.on('|').withKeyValuePairs(':").split() returns an unmodifiable Map, so I need to walk through Map until id key and put entries into a new Map in this case. It does not looks an effective solution.
String.substring(0, String.indexOf('|', String.indexOf("id"))) is not an option because "id" String can be substring of any value before id key.
Or I can use two splitter, entrySplitter to split string into entries and keyValueSplitter to split entries into key-value pairs and then put them into a map while specific key hasn't been reached.
What is the best solution?
Other than copying the output of MapSplitter to another Map and manipulate that (assuming the keys order is preserved), I see no other solution than partially parsing yourself.
Your remark about "id" possibly appearing elsewhere is correct, so you need to search something more specific, like |id:...| or id:...| if id is the first key.
private static final Pattern ID_REGEX = Pattern.compile("(^|\\|)id:.+?\\|");
...
Matcher matcher = ID_REGEX.matcher(line);
if (matcher.find()) {
lineForMapSplitter = line.substring(0, matcher.end()-1);
}
First of all, don't use Splitter.MapSplitter directly, but rather Splitter#withKeyValueSeparator (here: Splitter.on('|').withKeyValueSeparator(':'). Secondly, in your case the most efficient way would be manually split pairs and then split pairs if your predicate (about key == id) is not met, and not create map until the very end.
TIMTOWDI, but I'm using jOOL, which has useful methods for your use case. Seq.seq(Iterable) is a simple helper for creating stream and, what's more important, Seq#limitUntilClosed(Predicate) will pick up all values until it finds id key:
private static final Splitter PAIRS_SPLITTER = Splitter.on('|');
private static final Splitter KEY_VALUE_SPLITTER = Splitter.on(':');
private static final String INVALID_ENTRY_MESSAGE = "Chunk [%s] is not a valid entry";
private Map<String, String> homebrewMapSplitter(final String string)
{
return Seq.seq(PAIRS_SPLITTER.split(string))
.map(this::createEntry)
.limitUntilClosed(e -> e.getKey().equals("id"))
.collect(ImmutableMap.toImmutableMap(
Map.Entry::getKey,
Map.Entry::getValue)
);
}
// ~copied from MapSplitter#split(CharSequence)
private Map.Entry<String, String> createEntry(final String entry)
{
Iterator<String> entryFields = KEY_VALUE_SPLITTER.split(entry).iterator();
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String key = entryFields.next();
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String value = entryFields.next();
checkArgument(!entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
return Maps.immutableEntry(key, value);
}

More succinct way of creating a constant String map in Java

Good day all,
Considering the following code example:
import java.util.HashMap;
import java.util.Map;
public class StaticPractice {
private final Map<String, String> mapperMap;
public StaticPractice(){
mapperMap = new HashMap<String, String>();
mapperMap.put("Foo1", "Bar1");
mapperMap.put("Foo2", "Bar1");
mapperMap.put("Foo3", "Bar2");
mapperMap.put("Foo3", "Bar3");
//...
mapperMap.put("MoreFoo", "BarAgain");
}
public void doSomething(){
//use mapperMap
}
}
I am looking for a more succinct way of creating a Map data structure that has a whole lot of constant Strings mapping to a whole lot of other constant Strings. In use, the example is far from "clean" or elegant, and is very verbose (there are alot of predefined constant mappings).
The goal of the class is to map objects referenced by these predefined constant Strings. It is commonplace in my particular code convention to use private static final String for all String constant, this example as well breaks that convention.
Would greatly appreciate any input, the wealth of knowledge from SO contributors always humbles me.
Much thanks.
Edit: Requirement specifies no external files.
One approach would be to create a builder class that generates the map. This has the advantage that you can optimize for concise syntax. You can also do things like making the generated map immutable -- useful if you want to use it as a publically accessible constant.
In your example, I notice that you have more than one key mapping to the same value. So, it would be more concise to have a method that takes a value followed by a list of keys. You can also make it more concise by having the builder return itself so that you can "chain" method calls:
class Builder<K,V> {
final Map<K,V> map = new HashMap<K,V>();
Builder add(V value, K... keys) {
for(K key : keys) {
map.put(key, value);
}
return this;
}
Map<K,V> build() {
return Collections.unmodifiableMap(new HashMap<K,V>(map));
}
}
// Usage:
mapperMap = new Builder<String,String>()
.add("Bar1", "Foo1", "Foo2")
.add("Bar2", "Foo3")
...
.build();
Alternately you might take a look at the Guava ImmutableMap class, which has a builder using the chaining syntax, though it doesn't have a way to map multiple keys to a single value in one call.
I Think you can try using Properties instead of map or initializing the map by reading strings from a configration file.
The most succint way I know is to define your map as an anonymous subclass of HashMap with an instance initializer:
private final Map<String, String> mapperMap =
Collections.unmodifiableMap(new HashMap() {{ // instance initializer
put("Foo1", "Bar1");
put("Foo2", "Bar1");
put("Foo3", "Bar2");
put("Foo3", "Bar3");
}});
If you want it to be a final String, you can always create a class with a couple of constant strings and the use a list of objects of that class.
You can do it like this:
class MapClass {
private static final String key;
private static final String value;
}
List<MapClass> l = new ArrayList<>();

adding a key to HashMap without the value?

Is there a way to add a key to a HashMap without also adding a value? I know it seems strange, but I have a HashMap<String, ArrayList<Object>> amd I want to first be able to create keys as needed and then check if a certain key exists and, if so, put the appropriate value, namely the ArrayList<Object>
Was that confusing enough?
Since you're using a Map<String, List<Object>>, you're really looking for a multimap. I highly recommend using a third-party library such as Google Guava for this - see Guava's Multimaps.
Multimap<String, Object> myMultimap = ArrayListMultimap.create();
// fill it
myMultimap.put("hello", "hola");
myMultimap.put("hello", "buongiorno");
myMultimap.put("hello", "สวัสดี");
// retrieve
List<String> greetings = myMultimap.get("hello");
// ["hola", "buongiorno", "สวัสดี"]
Java 8 update: I'm no longer convinced that every Map<K, SomeCollection<V>> should be rewritten as a multimap. These days it's quite easy to get what you need without Guava, thanks to Map#computeIfAbsent().
Map<String, List<Object>> myMap = new HashMap<>();
// fill it
myMap.computeIfAbsent("hello", ignored -> new ArrayList<>())
.addAll(Arrays.asList("hola", "buongiorno", "สวัสดี");
// retrieve
List<String> greetings = myMap.get("hello");
// ["hola", "buongiorno", "สวัสดี"]
I'm not sure you want to do this. You can store null as a value for a key, but if you do how will be able to tell, when you do a .get("key") whether the key exists or if it does exist but with a null value? Anyway, see the docs.
You can put null values. It is allowed by HashMap
You can also use a Set initially, and check it for the key, and then fill the map.
Yes, it was confusing enough ;) I don't get why you want to store keys without values instead just putting empty arraylists instead of null.
Adding null may be a problem, because if you call
map.get("somekey");
and receive a null, then you do not know, if the key is not found or if it is present but maps to null...
//This program should answer your questions
import java.util.*;
public class attemptAddingtoHashMap { //Start of program
//MAIN METHOD #################################################
public static void main(String args[]) { //main begins
Map<String, ArrayList<Object>> hmTrial = new HashMap<String, ArrayList<Object>>();
ArrayList alTrial = new ArrayList();//No values now
if (hmTrial.containsKey("first")) {
hmTrial.put("first", alTrial); }
else {hmTrial.put("first",alTrial);}
//in either case, alTrial, an ArrayList was mapped to the string "first"
//if you choose to, you can also add objects to alTrial later
System.out.println("hmTrial is " + hmTrial); //empty now
alTrial.add("h");
alTrial.add("e");
alTrial.add("l");
alTrial.add("l");
alTrial.add("o");
System.out.println("hmTrial is " + hmTrial);//populated now
} //end of main
//#############################################################################################################
} //end of class
//Note - removing objects from alTrial will remove the from the hashmap
//You can copy, paste and run this code on https://ide.geeksforgeeks.org/

Categories