So currently I have a
static List<List<String>> lines = new ArrayList<>();
with the Arraylist containing values such as
{["ID", "Last Name", "First Name", "Vaccine Type", "Vaccination Date", "Vaccine Location"]
["12345", "Doe", "John", "Pfizer", "10/30/2020", "Argentina"]
["54321", "Adam", "Marceline", "Pfizer", "11/19/2020", "Russia"]
["70513", "Sitz", "Tomislav", "Moderna", "12/2/2020", "England"]
["54371", "Lyndon", "Sergei", "Johnson&Johnson", "03/01/2021", "Israel"]
["41027", "Chambers", "Wallis", "Moderna", "01/28/2021", "United States"]
}
I want to find the number of unique vaccine types as well as find the frequency of it. So for example this arraylist should return something like
"Pfizer:2, Moderna:2, J&J:1"
ideally in it's own seperate data structure(array).
I tried using a HashList but the way my arraylist is formatted is not supported.
Set<String> unique = new HashList<String>(lines);
for (String key : unique) {
System.out.println(key + ": " + Collections.frequency(lines, key));
}
I get the error "the hashlist cannot be resolved to type".
Map<String,Integer> map = new HashMap<>();
for(list<String> l : lines) {
String name = l.get(3);
int count = map.getOrDefault(name,0);
count++;
map.put(name,count)
}
//now iterate the map and print all the values
Map<String, Long> result = lines.stream().collect(Collectors.groupingBy(list -> list.get(3), Collectors.counting()));
produces: // {Pfizer=2, Moderna=2, Johnson&Johnson=1}
A cleaner way would have been to map each list of strings into a corresponding object and then stream through those, but that is for you to refactor :)
Related
I have the following JSON file:
{
"meta" : {
"stock" : "AWS",
"date modified" : 90
},
"roles" : [ "Member", "Admin" ],
"name" : "John Doe",
"admin" : true,
"email" : "john.doe#example.com"
}
I wanted to both read the values of the keys and add them to an Array List.
try {
// create object mapper instance
ObjectMapper mapper = new ObjectMapper();
// convert JSON file to map
Map<?, ?> map = mapper.readValue(Paths.get("user.json").toFile(), Map.class);
ArrayList<String> data = new ArrayList<String>();
// print map entries
for (Map.Entry<?, ?> entry : map.entrySet()) {
System.out.println((entry.getClass()) + " " + entry.getValue());
data.add((String)entry.getValue()); // trying to add entry values to arraylist
}
} catch (Exception ex) {
ex.printStackTrace();
}
I'm able to print out the data type of the value along with the value itself. All the values are part of class java.util.LinkedHashMap$Entry. I'm not able to cast the values to a String to add them to an ArrayList. How should I go about doing this? Thanks
From the jackson-databind documentation you can convert your json to a Map<String, Object> map with the following line (you have boolean, list, number and string values in your json) :
Map<String, Object> map = mapper.readValue(json, Map.class);
// it prints {meta={stock=AWS, date modified=90}, roles=[Member, Admin], name=John Doe, admin=true, email=john.doe#example.com}
System.out.println(map);
If you want to save your map values string representation into an ArrayList data you can iterate over them with a loop :
List<String> data = new ArrayList<>();
for (Object value : map.values()) {
data.add(value.toString());
}
//it will print [{stock=AWS, date modified=90}, [Member, Admin], John Doe, true, john.doe#example.com]
System.out.println(data);
Your data type of entries will be like:
meta: Map<String:Object>
roles: List<String>
admin: Boolean
So you will get an exception when casting to string for each entry value.
You should handle different data type and convert it according to your request:
Object value = entry.getValue();
I highly recommend you write more few functions to check and convert map/list/primitive variables to expected data (String):
boolean isList(Object obj);
boolean isMap(Object obj);
...
public List<String> convertMap(Map<String,Object> map);
...
I Have json like this :
{
"lastModifiedBy" :"value",
"lastModifiedBy.$oid": "1234567189",
"displayedBy" : 0,
"displayedBy.one" : "Abhi",
"displayedBy.one.new" : "Sammy",
"displayedBy.two":"random_value3",
"a.b":null,
"b.c":null,
"d.e.f":null
}
I only want to keep the longest keys and not the previous state parent without affecting the other keys
output I need:
{
"lastModifiedBy.$oid": "1234567189",
"displayedBy.one.new" : "Sammy",
"displayedBy.two":"random_value3",
"a.b":null,
"b.c":null,
"d.e.f":null
}
Is there a way to do this in Jackson or any other java package.?
If you are able to convert it into an ArrayList, remove all keys you dont need. For example with foreach.
If you are able to convert it into an String split at ":" and "," remove the "s create an ArrayList and populate it by using index 0,2,4... as key and 1,3,5... as value and do the thing mentioned above.
Try this.
Map<String, String> map = new HashMap<>();
map.put("lastModifiedBy", "value");
map.put("lastModifiedBy.$oid", "1234567189");
map.put("displayedBy", "0");
map.put("displayedBy.one", "Abhi");
map.put("displayedBy.one.new", "Sammy");
map.put("displayedBy.two", "random_value3");
map.put("a.b", null);
map.put("b.c", null);
map.put("d.e.f", null);
List<String> removes = new ArrayList<>();
for (String parent : map.keySet())
for (String child : map.keySet())
if (parent != child && child.startsWith(parent)) {
removes.add(parent);
break;
}
for (String key : removes)
map.remove(key);
System.out.println(map);
output:
{a.b=null, d.e.f=null, displayedBy.one.new=Sammy, b.c=null, displayedBy.two=random_value3, lastModifiedBy.$oid=1234567189}
I need to map dynamimc json nested object into hashmap I could come up with solution but I couldn't get expected output.
Here is code
HashMap<String, Object> map = new Gson().fromJson(dynamicJson, HashMap.class);
String keys = map.keySet().stream().collect(Collectors.joining(", "));
String values = map.values().stream().map(obj -> String.valueOf(obj)).collect(Collectors.joining(", "));
System.out.println("Keys: " + keys);
System.out.println("Values: " + values);
Sample Json
{
"name": "Notification 2",
"message": "Facebook",
"tags":[
{
"city" : "Matara",
"village" : "Mirissa"
}
]
}
Actual output :
name, message, tags Notification 2, Facebook, [{city=Matara,
village=Mirissa}]
Expected output
name, message, tags/city, tag/village
Notification 2, Facebook, Matara, Mirissa
In above logic you are not processing sub elements, check below code
HashMap<String, Object> map = new Gson().fromJson(dynamicJson, HashMap.class);
Map<String, String> keyValueMap = new HashMap<>();
map.forEach((key, value) -> {
if (value instanceof List) {
((List)value).stream().forEach(obj -> { // processing sub elements
if (obj instanceof Map) {
((Map)obj).forEach((k,v) -> {
keyValueMap.put(key+"/"+k, v.toString());
});
}
});
} else { // direct value, no subelement
keyValueMap.put(key, value.toString());
}
});
The above logic will work for only elements which are inside List, so you need modify above logic little more generic based on your input json structure.
Below logic is to print the data which can be optimzed , i have written below logic so that it will be easy to understand
keyValueMap.forEach((k, v) -> {
System.out.print(k+ ",");
});
System.out.println();
keyValueMap.forEach((k, v) -> {
System.out.print(v+ ",");
});
it will give out put as below
name,tags/city,message,tags/village,
Notification 2,Matara,Facebook,Mirissa,
Thanks
Prasad
I've created a hash map that groups unique keys that combine three parameters, i.e. customer, sc and admin. I want to create a unique list of keys with a list of servers attached. I've implemented the following:
public static void main(String[] args) {
String items = "customer1^sc1^admin1|server1~" +
"customer1^sc1^admin1|server2~" +
"customer1^sc1^admin1|server3~" +
"customer2^sc1^admin1|server1~" +
"customer3^sc1^admin1|server3~" +
"customer3^sc1^admin1|server2~";
// Set up raw data
List<String> splitItems = Arrays.asList(items.split("\\s*~\\s*"));
// Display raw data
System.out.println("Raw List: " + items);
// Create a hash map containing customer name as key and list of logs as value
HashMap<String, List<String>> customerHashMap = new HashMap<>();
// Loop through raw data
for (String item : splitItems) {
// Create new lists. One for customers and one for logs
// List<String> customerList = new ArrayList<>();
List<String> logList;
String list[] = item.split("\\|");
String customer = list[0];
String log = list[1];
logList = customerHashMap.get(customer);
if (logList == null){
logList = new ArrayList<>();
customerHashMap.put(customer, logList);
}
logList.add(log);
// System.out.println(logList);
}
// Print out of the final hash map. Customer "a" should only have "a" logs, customer "b" with "b", etc.
System.out.println("");
List<String> hashMapList = new ArrayList<String>();
Iterator it = customerHashMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String output = pair.getKey() + "|" + pair.getValue().toString();
hashMapList.add(output);
it.remove();
}
String hashMapResultString = hashMapList.toString();
String hashMapResultFormatted = hashMapResultString.replaceAll("[\\[\\]]", "");
System.out.println(hashMapResultFormatted);
}
Raw List: customer1^sc1^admin1|server1~customer1^sc1^admin1|server2~customer1^sc1^admin1|server3~customer2^sc1^admin1|server1~customer3^sc1^admin1|server3~customer3^sc1^admin1|server2~
Hash Map String:
customer2^sc1^admin1|server1, customer3^sc1^admin1|server3, server2, customer1^sc1^admin1|server1, server2, server3
I now want to use the hash map to create a string which will be parsed further (don't ask lol). So I set the keys and values of the hash map to a string which separates them with a unique delimiter |. The problem is that because the key is a List<String>, when printing I can't ascertain the beginning of every new key if its value is a list with more than one item, i.e. customer3^sc1^admin1|server3, server2, is followed immediately by customer1^sc1^admin1|server1, server2, server3. I need a delimiter here that separates them.
My ideal output would look like this:
customer2^sc1^admin1|server1~customer3^sc1^admin1|server3, server2~customer1^sc1^admin1|server1, server2, server3~...
How can I achieve this?
Update:
This is the answer I ultimately found useful for my particular problem:
StringBuilder s = new StringBuilder();
for (Map.Entry<String, List<String>> entry : customerHashMap.entrySet()) {
s.append(entry.getKey() + "|");
List<String> list = entry.getValue();
for (String item : list) {
if (item != list.get(list.size() - 1)) {
s.append(item + "^");
} else {
s.append(item);
}
}
s.append("~");
}
System.out.println(s.toString());
You can iterate through a map's entry set:
StringBuilder s = new StringBuilder();
for(Map.Entry<String,List<String>> entry : map.entrySet()) {
s.append(entry.getKey() + "\n");
List<String> list = entry.getValue();
for(String item : list) {
s.append(" " + item + "\n");
}
}
return s.toString();
For the sake of a clearer example, I've output a different format from the one you asked for, but this illustrates how to work with a map of list values. When adapting to your needs, have a look at java.util.StringJoiner and the related Collectors.joining(); it may well be useful.
Streams can be handy here:
String encoded = map.entrySet().stream()
.map( entry -> entry.getValue().stream()
.collect(Collectors.joining("^"))
+ "|" + entry.getKey())
.collect(Collectors.joining("~"));
What happens here is:
We get a stream of Entry<String,List<String> out of the map
The lambda entry -> ... converts each entry into a string of the form val1^v2^v3^...^valN|key, i.e. we are mapping a Stream<Entry<>> into a Stream<String>.
the final collect() joins the stream of strings into a single string using ~ as a delimiter.
All,
I have a map with categories and subcategories as lists like this:
Map<String,List<String>> cat = new HashMap<String,List<String>>();
List<String> fruit = new ArrayList<String>();
fruit.add("Apple");
fruit.add("Pear");
fruit.add("Banana");
cat.put("Fruits", fruit);
List<String> vegetable = new ArrayList<String>();
vegetable.add("Carrot");
vegetable.add("Leak");
vegetable.add("Parsnip");
cat.put("Vegetables", vegetable);
I want to find if "Carrot" is in the map and to which key ("Fruit') it matches, however:
if (cat.containsValue("Carrot")) {System.out.println("Cat contains Leak");}
gives False as outcome. How can I match "Carrot" and get back the key value "Vegetable"
Thx.
You need to create the inversed map:
Map<String, String> fruitCategoryMap = new HashMap<>();
for(Entry<String, List<String>> catEntry : cat.entrySet()) {
for(String fruit : catEntry.getValue()) {
fruitCategoryMap.put(fruit, catEntry.getKey());
}
}
Then you can simply do:
String category = fruitCategoryMap.get("Banana"); // "Fruit"
Iterate thought all the keys and check in the value if found then break the loop.
for (String key : cat.keySet()) {
if (cat.get(key).contains("Carrot")) {
System.out.println(key + " contains Carrot");
break;
}
}
You have to search for the value in the entire map:
for (Entry<String, List<String>> entry : cat.entrySet()) {
for (String s : entry.getValue()) {
if (s.equals("Carrot"))
System.out.println(entry.getKey());
}
}
try this,
for (Map.Entry<String, List<String>> entry : cat.entrySet()) {
String names[] = entry.getValue().toArray(new String[entry.getValue().size()]);
for (int i = 0; i < names.length; i++) {
if (names[i].equals("Carrot")) {
System.out.println("found"+names[i]);
break;
}
}
}