What is the optimum way to count the unique number of words in a propertyfile (Just the Values) in java (java 1.8)
for example entries may be:
key1=This is my value for error {0}
key2=This is success message.Great.
Output should be 10 (including {0})
What I tried
property.load(in);
Enumeration em = property.keys();
while (em.hasMoreElements()) {
String str = (String) em.nextElement();
completeString =completeString+property.get(str);
}
Set<String> myset=new HashSet<>();
String s[]=completeString.split("[ .]");
for(int i=1;i<s.length;i++){
myset.add(s[i]);
}
for (String sss: myset){
System.out.println(sss);
}
System.out.println(myset.size());
Do we have a simpler way in java 1.8
Data used :
I used a dummy Properties
Properties prop = new Properties();
prop.put("A", "This is my value for error {0}");
prop.put("B", "This is success message.Great.");
Good old Java:
Using the same logic you used, you can simply split the String of each property in the iteration :
Set<String> set = new HashSet<>();
Enumeration em = property.keys();
while (em.hasMoreElements()) {
String str = (String) em.nextElement();
for(String s : str.split("[ .]")){
set.add(s);
}
}
In Java 8 - Stream API :
Define the pattern to split each "word".
Pattern pattern = Pattern.compile("[ .]");
Now, first let's get our Stream<String> for our values.
You can either take a List<Object> :
Stream<String> stream =
//Create a `List<Object>` from the enumeration and stream it
Collections.list(prop.elements()).stream()
//Convert in String
.map(o -> (String)o);
Or Stream the Map.Entry of the Properties :
Stream<String> stream =
prop.entrySet().stream() //Iterate the Map.Entry<Object,Object>
.map(e -> (String)e.getValue())
(Not sure which is more efficient)
Then, all you have to do is to flatMap the Stream to split each String into new Stream<String>.
stream.flatMap(pattern::splitAsStream) //split based on the pattern define and return a new `Stream<String>`
Then collect the Stream into a Set
.collect(Collectors.toSet()); //collect in a `Set<String>`
The result would be a nice Set printed like:
[Great, success, for, This, {0}, is, my, error, message, value]
Summary :
Set<String> set =
prop.entrySet().stream()
.map(e -> (String)e.getValue())
.flatMap(Pattern.compile(pattern)::splitAsStream)
.collect(Collectors.toSet());
Related
I want to create a nested HashMap which returns the frequency of terms among multiple files. Like,
Map<String, Map<String, Integer>> wordToDocumentMap=new HashMap<>();
I have been able to return the number of times a term appears in a file.
Map<String, Integer> map = new HashMap<>();//for frequecy count
String str = "Wikipedia is a free online encyclopedia, created and edited by
volunteers around the world."; //String str suppose a file a.java
// The query string
String query = "edited Wikipedia volunteers";
// Split the given string and the query string on space
String[] strArr = str.split("\\s+");
String[] queryArr = query.split("\\s+");
// Map to hold the frequency of each word of query in the string
Map<String, Integer> map = new HashMap<>();
for (String q : queryArr) {
for (String s : strArr) {
if (q.equals(s)) {
map.put(q, map.getOrDefault(q, 0) + 1);
}
}
}
// Display the map
System.out.println(map);
In my code its count the frequency of the given query Individually. But I want to Map the query term and its frequency with its filenames. I have searched around the web for a solution but am finding it tough to find a solution that applies to me. Any help would be appreciated!
I hope I'm understanding you correctly.
What you want is to be able to read in a list of files and map the file name to the map you create in the code above. So let's start with your code and let's turn it into a function:
public Map<String, Integer> createFreqMap(String str, String query) {
Map<String, Integer> map = new HashMap<>();//for frequecy count
// The query string
String query = "edited Wikipedia volunteers";
// Split the given string and the query string on space
String[] strArr = str.split("\\s+");
String[] queryArr = query.split("\\s+");
// Map to hold the frequency of each word of query in the string
Map<String, Integer> map = new HashMap<>();
for (String q : queryArr) {
for (String s : strArr) {
if (q.equals(s)) {
map.put(q, map.getOrDefault(q, 0) + 1);
}
}
}
// Display the map
System.out.println(map);
return map;
}
OK so now you have a nifty function that makes a map from a string and a query
Now you're going to want to set up a system for reading in a file to a string.
There are a bunch of ways to do this. You can look here for some ways that work for different java versions: https://stackoverflow.com/a/326440/9789673
lets go with this (assuming >java 11):
String content = Files.readString(path, StandardCharsets.US_ASCII);
Where path is the path to the file you want.
Now we can put it all together:
String[] paths = ["this.txt", "that.txt"]
Map<String, Map<String, Integer>> output = new HashMap<>();
String query = "edited Wikipedia volunteers"; //String query = "hello";
for (int i = 0; i < paths.length; i++) {
String content = Files.readString(paths[i], StandardCharsets.US_ASCII);
output.put(paths[i], createFreqMap(content, query);
}
The string can be
"accountno=18&username=abc&password=1236" or "username=abc&accountno=18&password=1236" or the accountno can be present anywhere in the string.
I need to get the accountno details from this string using a key value pair. I used spilt on "&" but I'm unable to get the result.
import java.util.regex.*;
public class RegexStrings {
public static void main(String[] args) {
String input = "accountno=18&username=abc&password=1236";
String exten = null;
Matcher m = Pattern.compile("^accountno: (.&?)$", Pattern.MULTILINE).matcher(input);
if (m.find()) {
exten = m.group(1);
}
System.out.println("AccountNo: "+exten);
}
}
How can I get the accountno value from this above string as key value pair in java
You may handle this by first splitting on & to isolate each key/value pair, then iterate that collection and populate a map:
String input = "accountno=18&username=abc&password=1236";
String[] parts = input.split("&");
Map<String, String> map = new HashMap<>();
for (String part : parts) {
map.put(part.split("=")[0], part.split("=")[1]);
}
System.out.println("account number is: " + map.get("accountno"));
This prints:
account number is: 18
Using some simple tools, like string.split and Map, you can easly do that:
Map<String, String> parse(String frase){
Map<String, String> map = new TreeMap<>();
String words[] = frase.aplit("\\&");
for(String word : words){
String keyValuePair = word.split("\\=");
String key = keyValuePair[0];
String value = keyValuePair[1];
map.put(key, value);
}
return map;
}
To get a specific value, like "accountno", just retrive that key map.get("accountno")
The same answer mentioned by #vinicius can be achieved using Java 8 by :
Map<String, String> map = Arrays.stream(input.split("&"))
.map(str -> str.split("="))
.collect(Collectors.toMap(s -> s[0],s -> s[1]));
//To retrieve accountno from map
System.out.println(map.get("accountno"));
As you said
the accountno can be present anywhere in the string
String input = "accountno=18&username=abc&password=1236";
//input = "username=abc&accountno=19&password=1236";
Matcher m = Pattern.compile("&?accountno\\s*=\\s*(\\w+)&?").matcher(input);
if (m.find()) {
System.out.println("Account no " + m.group(1));
}
This would work even when accountno is somewhere in the middle of the string
Output:
Account no 18
You can try out regex here:
https://regex101.com/r/nOHmzc/2
I currently have a TreeMap of the form <String, List<List<String>>
I'm trying to write my tree map to an output file where I get the inner values of my string[] all separated by a colon.
Do I need a second for loop to loop through each inner list and format it using a .join(":", elements)?
Or is there a more concise way to keep it all in a single for loop statement?
I've tried a few things and my current code is:
new File(outFolder).mkdir();
File dir = new File(outFolder);
//get the file we're writing to
File outFile = new File(dir, "javaoutput.txt");
//create a writer
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"))) {
for (Map.Entry<String, String[]> entry : allResults.entrySet()) {
writer.write(entry.getKey() + ", "+ Arrays.toString(entry.getValue()).replace("null", "").toString());
writer.newLine();
}
Current output:
ANY, [[469, 470], [206, 1013, 1014], [2607, 2608]]
Desired output:
ANY, 469:470, 206:1013:1014, 2607:2608
Any suggestions would be greatly appreciated.
String.join(":", arr) can be used to take the String array and return a colon-separated String. This can then be used with Streams with a Collector to join these strings with a comma-separator, so :
TreeMap<String, String[]> allResults = new TreeMap<>();
allResults.put("a", new String[]{"469", "470"});
allResults.put("b", new String[]{"206", "1013", "1014"});
allResults.put("c", new String[]{"2607", "2608"});
String result = allResults.entrySet().stream()
.map(e -> String.join(":", e.getValue()))
.collect(Collectors.joining(", "));
System.out.println(result);
produces :
469:470, 206:1013:1014, 2607:2608
With a List<List<String>>, you need a stream within a stream, so :
TreeMap<String, List<List<String>>> allResults = new TreeMap<>();
allResults.put("a", Arrays.asList(Arrays.asList("469", "470"), Arrays.asList("206", "1013", "1014"), Arrays.asList("2607", "2608")));
allResults.put("b", Arrays.asList(Arrays.asList("169", "470")));
allResults.put("c", Arrays.asList(Arrays.asList("269", "470")));
String result = allResults.entrySet().stream()
.map(i -> i.getKey() + "," + i.getValue().stream().map(elements -> String.join(":", elements))
.collect(Collectors.joining(", "))
)
.collect(Collectors.joining("\n"));
System.out.println(result);
which produces :
a,469:470, 206:1013:1014, 2607:2608
b,169:470
c,269:470
I have one String value which I am getting from one of svo,
i.e. String reply=svo.getReplies();
The output that I am getting is like --> "1:true,2:false,3:true,4:false,5:false,6:false"
Now what I want is to separate storage of the reply and store all replies in new variables for every reply. For example:
String firstVal= "true";
String secondeVal= "false";
// ... and so on.
How can I do it?
You can make Map from this string. And then use that map as you need.
For example: String firstVal = map.get(1);
String s1 = "1:true,2:false,3:true,4:false,5:false,6:false";
Map<Integer, String> map = new HashMap<>();
for (String s : s1.split(",")){
map.put(Integer.parseInt(s.substring(0, s.indexOf(":"))), s.substring(s.indexOf(":")+1));
}
for (Integer key : map.keySet()) System.out.println(key + " " + map.get(key));
That is not possible in java unless you use a for loop, how ever you can use String#split(","); to split the string into a String[]
I wrote some example code for you, using the Map Interface:
public class splitstringexample {
public static void main(String[] args) {
String reply = "1:true,2:false,3:true,4:false,5:false,6:false";
Map<String, Boolean> example = splitString(reply);
for (String name: example.keySet()){
String key =name.toString();
String value = example.get(name).toString();
System.out.println(key + " " + value);
}
}
public static Map<String,Boolean> splitString(String reply){
Map<String, Boolean> mapping = new HashMap<>();
String[] mappings = reply.split(",");
for(String s : mappings) {
String[] parts = s.split(":");
mapping.put(parts[0],Boolean.parseBoolean(parts[1]));
}
return mapping;
}
}
With a map object you can then use mapObject.get(<identifier>) to access the corresponding boolean value. In your case mapObject.get("1") would return true,mapObject.get("2") false and so on
You can achieve that with a regular expression :
//Compile the regular expression patern
Pattern p = Pattern.compile("([0-9]+):(true|false)+?") ;
//match the patern over your input
Matcher m = p.matcher("1:true,2:false,3:true,4:false,5:false,6:false") ;
// iterate over results (for exemple add them to a map)
Map<Integer, Boolean> map = new HashMap<>();
while (m.find()) {
// here m.group(1) contains the digit, and m.group(2) contains the value ("true" or "false")
map.put(Integer.parseInt(m.group(1)), Boolean.parseBoolean(m.group(2)));
System.out.println(m.group(2)) ;
}
More informations abour regular expressions syntax can be found here :
https://docs.oracle.com/javase/tutorial/essential/regex/index.html
EDIT : changed the list to a Map
Using replaceFirst and spliting it with regex: ,\\d: and store each value in an array
String str = "1:true,2:false,3:true,4:false,5:false,6:false".replaceFirst("1:","");
String[] strArray = str.split(",\\d:");
System.out.println(Arrays.toString(strArray));
output
[true, false, true, false, false, false]
You can use a Pattern and Stream over the matching results applied to the String returrned by svo.getReplies():
String input = "1:true,2:false,3:true,4:false,5:false,6:false";
String[] result = Pattern.compile("(true|false)")
.matcher(input)
.results()
.map(MatchResult::group)
.toArray(String[]::new);
System.out.println(Arrays.toString(result)); // [true, false, true, false, false, false]
String firstVal = result[0]; // true
String secondVal = result[1]; // false
// ...
I have a string :
My name is amit
and a mapping :
My -> 1121
name -> 1122
is -> 1123
amit -> 1124
I want to get back :
1121 1122 1123 1124
where every word is mapped to its corresponding long value which is held in a HashMap.
Here is my version:
public String delimtedStringToLong(String input, String delimiter, Map<String, Long> map) {
String[] arr = input.split(delimiter);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
sb.append(String.valueOf(map.get(arr[i])) + delimiter);
}
return sb.toString();
}
I am doing this in Java 8. Can there be better approach for this. Thanks!
I'd split the input string, stream it through a mapping function that takes the value from the map and then collect it back:
String input = "My name is amit";
Map<String, Long> map = new HashMap<>();
map.put("My", 1121L);
map.put("name", 1122L);
map.put("is", 1123L);
map.put("amit", 1124L);
String output =
Arrays.stream(input.split(" "))
.map(s -> String.valueOf(map.get(s)))
.collect(Collectors.joining());