Find unique value of string array and keep order - java

I have a String[] with values like so:
line_str = "1,3,4,3,11,2,2,6,7"
I want to find unique value and keep the arrangement of value
unique_str="1,3,4,11,2,6,7"
I'm using a HashSet but the output is:
[1,6,7,4,11,3,2]
Here is my code:
String line_str = "1,3,4,3,11,2,2,6,7";
String[] str_arr = line_str.split(",");
Set<String> uniqueValue = new HashSet<>(Arrays.asList(str_arr));
Toast.makeText(this, uniqueValue.toString(),Toast.LENGTH_LONG).show();

A HashSet will ensure no duplications and a LinkedHashSet will ensure each element remains in its designated position;
String line_str = "1,3,4,3,11,2,2,6,7";
String[] str_arr = line_str.split(",");
Set<Integer> uniqueNumbers = new LinkedHashSet<Integer>();
for(String num : str_arr) {
uniqueNumbers.add(Integer.parseInt(num));
}
If your input has any variance then you will need to handle that.

Using streams :
String line_str = "1,3,4,3,11,2,2,6,7";
String unique_str = Pattern.compile(",")
.splitAsStream(line_str)
.distinct()
.collect(Collectors.joining(","));
System.out.println(unique_str);

Related

java invalid json string to map (without quotes on key) [duplicate]

How can I convert a String into a HashMap?
String value = "{first_name = naresh, last_name = kumar, gender = male}"
into
Map<Object, Object> = {
first_name = naresh,
last_name = kumar,
gender = male
}
Where the keys are first_name, last_name and gender and the values are naresh, kumar, male.
Note: Keys can be any thing like city = hyderabad.
I am looking for a generic approach.
This is one solution. If you want to make it more generic, you can use the StringUtils library.
String value = "{first_name = naresh,last_name = kumar,gender = male}";
value = value.substring(1, value.length()-1); //remove curly brackets
String[] keyValuePairs = value.split(","); //split the string to creat key-value pairs
Map<String,String> map = new HashMap<>();
for(String pair : keyValuePairs) //iterate over the pairs
{
String[] entry = pair.split("="); //split the pairs to get key and value
map.put(entry[0].trim(), entry[1].trim()); //add them to the hashmap and trim whitespaces
}
For example you can switch
value = value.substring(1, value.length()-1);
to
value = StringUtils.substringBetween(value, "{", "}");
if you are using StringUtils which is contained in apache.commons.lang package.
You can do it in single line, for any object type not just Map.
(Since I use Gson quite liberally, I am sharing a Gson based approach)
Gson gson = new Gson();
Map<Object,Object> attributes = gson.fromJson(gson.toJson(value),Map.class);
What it does is:
gson.toJson(value) will serialize your object into its equivalent Json representation.
gson.fromJson will convert the Json string to specified object. (in this example - Map)
There are 2 advantages with this approach:
The flexibility to pass an Object instead of String to toJson method.
You can use this single line to convert to any object even your own declared objects.
String value = "{first_name = naresh,last_name = kumar,gender = male}"
Let's start
Remove { and } from the String>>first_name = naresh,last_name = kumar,gender = male
Split the String from ,>> array of 3 element
Now you have an array with 3 element
Iterate the array and split each element by =
Create a Map<String,String> put each part separated by =. first part as Key and second part as Value
#Test
public void testToStringToMap() {
Map<String,String> expected = new HashMap<>();
expected.put("first_name", "naresh");
expected.put("last_name", "kumar");
expected.put("gender", "male");
String mapString = expected.toString();
Map<String, String> actual = Arrays.stream(mapString.replace("{", "").replace("}", "").split(","))
.map(arrayData-> arrayData.split("="))
.collect(Collectors.toMap(d-> ((String)d[0]).trim(), d-> (String)d[1]));
expected.entrySet().stream().forEach(e->assertTrue(actual.get(e.getKey()).equals(e.getValue())));
}
try this out :)
public static HashMap HashMapFrom(String s){
HashMap base = new HashMap(); //result
int dismiss = 0; //dismiss tracker
StringBuilder tmpVal = new StringBuilder(); //each val holder
StringBuilder tmpKey = new StringBuilder(); //each key holder
for (String next:s.split("")){ //each of vale
if(dismiss==0){ //if not writing value
if (next.equals("=")) //start writing value
dismiss=1; //update tracker
else
tmpKey.append(next); //writing key
} else {
if (next.equals("{")) //if it's value so need to dismiss
dismiss++;
else if (next.equals("}")) //value closed so need to focus
dismiss--;
else if (next.equals(",") //declaration ends
&& dismiss==1) {
//by the way you have to create something to correct the type
Object ObjVal = object.valueOf(tmpVal.toString()); //correct the type of object
base.put(tmpKey.toString(),ObjVal);//declaring
tmpKey = new StringBuilder();
tmpVal = new StringBuilder();
dismiss--;
continue; //next :)
}
tmpVal.append(next); //writing value
}
}
Object objVal = object.valueOf(tmpVal.toString()); //same as here
base.put(tmpKey.toString(), objVal); //leftovers
return base;
}
examples
input : "a=0,b={a=1},c={ew={qw=2}},0=a"
output : {0=a,a=0,b={a=1},c={ew={qw=2}}}
Should Use this way to convert into map :
String student[] = students.split("\\{|}");
String id_name[] = student[1].split(",");
Map<String,String> studentIdName = new HashMap<>();
for (String std: id_name) {
String str[] = std.split("=");
studentIdName.put(str[0],str[1]);
}
You can use below library to convert any string to Map object.
<!-- https://mvnrepository.com/artifact/io.github.githubshah/gsonExtension -->
<dependency>
<groupId>io.github.githubshah</groupId>
<artifactId>gsonExtension</artifactId>
<version>4.1.0</version>
</dependency>
Using Java Stream:
Map<String, String> map = Arrays.stream(value.replaceAll("[{}]", " ").split(","))
.map(s -> s.split("=", 2))
.collect(Collectors.toMap(s -> s[0].trim(), s -> s[1].trim()));
Arrays.stream() to convert string array to stream.
replaceAll("[{}]", " "): regex version to replace both braces.
split(","): Split the string by , to get individual map entries.
s.split("=", 2): Split them by = to get the key and the value and ensure that the array is never larger than two elements.
The collect() method in Stream API collects all objects from a stream object and stored in the type of collection.
Collectors.toMap(s -> s[0].trim(), s -> s[1].trim()): Accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.

Convert a list of string into a comma separated string without duplications

I have a list of strings in Java. I would like to to insert it into a string with commas, something like:
Input: [option1,option2,option3,option1,option4]
Output: option1,option2,option3,option4
I saw this topic and I really liked this one:
StringBuilder result = new StringBuilder();
String delimiter= "";
for (String i : list) {
result.append(delimiter).append(i);
delimiter = ",";
}
return result.toString();
But what would be the best way to add support for unique only items? How can I return a string without any duplicates? I could remove duplication from list first but it feels like there is a better solution here.
The best to avoid duplicates is to use a Set
TreeSet for alphabetical order
LinkedHashSet to keep insertion order (initial order)
StringBuilder result = new StringBuilder();
String delimiter= "";
for (String i : new LinkedHashSet<String>(list)) {
result.append(delimiter).append(i);
delimiter = ",";
}
return result.toString();
But you can just do String.join(',', new LinkedHashSet<String>(list))
Back to List
List<String> inputList = (unique) ? new ArrayList<>(new HashSet<>(list)) : list;
Case-insensitive
Set<String> check = new HashSet<String>();
StringBuilder result = new StringBuilder();
String delimiter= "";
for (String i : list) {
if(!check.contains(i.toLowerCase())){
result.append(delimiter).append(i);
delimiter = ",";
check.add(i.toLowerCase());
}
}
return result.toString();
You can stream() the list and collect only distinct values. Afterwards, you can just String.join(...) them to a comma separated String, like this:
public static void main(String[] args) {
// example values
List<String> list = new ArrayList<>();
list.add("option1");
list.add("option2");
list.add("option3");
list.add("option4");
list.add("option1");
list.add("option3");
list.add("option5");
// stream the list and collect only distinct values in a new list
List<String> distinctOptions = list.stream()
.distinct()
.collect(Collectors.toList());
// then create a comma separated String from that list
String commaSeparatedUniqueStrings = String.join(",", distinctOptions);
// and print it
System.out.println(commaSeparatedUniqueStrings);
}
The output is
option1,option2,option3,option4,option5
Extra requirements from comments:
Limited to Java 7
Support unique flag
Handle case-sensitive
Optional: Alphabetical sort may be allowed
Sorted
If sorting the values is ok, handling case-sensitive is easiest done using a TreeSet with a case-insensitive Comparator, like the String.CASE_INSENSITIVE_ORDER, or by using a Collator for full language support.
static String toString(List<String> list, boolean unique) {
Collection<String> dataToProcess = list;
if (unique) {
dataToProcess = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
dataToProcess.addAll(list);
}
StringBuilder result = new StringBuilder();
String delimiter= "";
for (String s : dataToProcess) {
result.append(delimiter).append(s);
delimiter = ",";
}
return result.toString();
}
Test
List<String> list = Arrays.asList("option1", "option3", "OPTION1", "OPTION2", "option4", "option2");
System.out.println(toString(list, false));
System.out.println(toString(list, true));
Output
option1,option3,OPTION1,OPTION2,option4,option2
option1,OPTION2,option3,option4
Notice how the "unique" result is sorted, but the non-unique result is not.
Using Collator
For better language support, use a Collator:
if (unique) {
Collator collator = Collator.getInstance(/*Locale.GERMANY*/);
collator.setStrength(Collator.SECONDARY);
dataToProcess = new TreeSet<>(collator);
dataToProcess.addAll(list);
}
Unsorted
To do it without sorting the values, we'll keep using the TreeSet but build a new list.
if (unique) {
Collator collator = Collator.getInstance(/*Locale.GERMANY*/);
collator.setStrength(Collator.SECONDARY);
Set<String> set = new TreeSet<>(collator);
dataToProcess = new ArrayList<>();
for (String s : list)
if (set.add(s))
dataToProcess.add(s);
}
Output
option1,option3,OPTION1,OPTION2,option4,option2
option1,option3,OPTION2,option4

Remove duplicates form arraystring

I have filled in an ArrayList of strings with suppliernumbers. This list contains duplicates values so I want to delete them with the HashSet.
I get following error: Invalid expression as statement
On line => Set set = new HashSet(leveranciers); (Set underlined)
Any idea why?
String[] leveranciers = new String[wdContext.nodeShoppingCart().size()];
for(int i = 0; i<wdContext.nodeShoppingCart().size(); i++){
String productnumber = wdContext.nodeShoppingCart().getShoppingCartElementAt(i).getMatnr()
wdThis.wdGetAchatsIndirectController().GetDetails(productnumber, "NL");
leveranciers[i] = wdContext.currentEt_DetailsElement().getLifnr();
}
//Remove duplicates from array
Set<String> set = new HashSet<String>(leveranciers);
set.toArray(new String[0]);
for(int y = 0; y<set.size();y++){
PdfPTable table = GetTable(set[y]);
byte[] pdf = wdThis.wdGetAchatsIndirectController().GetPDFFromFolder("/intranetdocuments/docs/AchatsIndirect", table);
wdThis.wdGetAchatsIndirectController().PrintPDF(pdf);
}
HashSet doesn't have a constructor which accepts an array.
Have a look at HashSet documentation.
http://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html
You can achieve your goal by using Arrays.asList method like that:
final String[] strings = new String[] {"ab", "ba", "ab"};
final Set<String> set = new HashSet<String>(Arrays.asList(strings));

separating unique values in an algorithm

I am decomposing a series of 90,000+ strings into a discrete list of the individual, non-duplicated pairs of words that are included in the strings with the rxcui id values associated with each string. I have developed a method which tries to accomplish this, but it is producing a lot of redundancy. Analysis of the data shows there are about 12,000 unique words in the 90,000+ source strings, after I clean and format the contents of the strings.
How can I change the code below so that it avoids creating the redundant rows in the destination 2D ArrayList (shown below the code)?
public static ArrayList<ArrayList<String>> getAllWords(String[] tempsArray){//int count = tempsArray.length;
int fieldslenlessthan2 = 0;//ArrayList<String> outputarr = new ArrayList<String>();
ArrayList<ArrayList<String>> twoDimArrayList= new ArrayList<ArrayList<String>>();
int idx = 0;
for (String s : tempsArray) {
String[] fields = s.split("\t");//System.out.println(" --- fields.length is: "+fields.length);
if(fields.length>1){
ArrayList<String> row = new ArrayList<String>();
System.out.println("fields[0] is: "+fields[0]);
String cleanedTerms = cleanTerms(fields[1]);
String[] words = cleanedTerms.split(" ");
for(int j=0;j<words.length;j++){
String word=words[j].trim();
word = word.toLowerCase();
if(isValidWord(word)){//outputarr.add(word);
System.out.println("words["+j+"] is: "+word);
row.add(word_id);//WORD_ID NEEDS TO BE CREATED BY SOME METHOD.
row.add(fields[0]);
row.add(word);
twoDimArrayList.add(row);
idx += 1;
}
}
}else{fieldslenlessthan2 += 1;}
}
System.out.println("........... fieldslenlessthan2 is: "+fieldslenlessthan2);
return twoDimArrayList;
}
The output of the above method currently looks like the following, with many rxcui values for some name values, and with many name values for some rxcui:
How do I change the code above so that the output is a list of unique pairs of name/rxcui values, summarizing all relevant data from the current output while removing only the redundancies?
If you just need a Collection of all words, use a HashSet Sets are primarily used for contains logic. If you need to associate a value with your string use a HashMap
public HashSet<String> getUniqueWords(String[] stringArray) {
HashSet<String> uniqueWords = new HashSet<String>();
for (String str : stringArray) {
uniqueWords.add(str);
}
return uniqueWords;
}
This will give you a collection of all the unique Strings in your array. If you need an ID use a HashMap
String[] strList; // your String array
int idCounter = 0;
HashMap<String, Integer> stringIDMap = new HashMap<String, Integer>();
for (String str : strList) {
if (!stringIDMap.contains(str)) {
stringIDMap.put(str, new Integer(idCounter));
idCounter++;
}
}
This will provide you a HashMap with unique String keys and unique Integer values. To get an id for a String you do this:
stringIDMap.get("myString"); // returns the Integer ID associated with the String "myString"
UPDATE
Based on the question update from the OP. I recommend creating an object that holds the String value and the rxcui. You can then place these in a Set or HashMap using a similar implementation to the one provided above.
public MyObject(String str, int rxcui); // The constructor for your new object
MyObject mo1 = new MyObject("hello", 5);
Either
mySet.add(myObject);
will work or
myMap.put(mo1.getStr, mo1.getRxcui);
What is the purpose of the unique word ID? Is the word itself not unique enough since you are not keeping duplicates?
A very basic way would be to keep a counter going as you are checking new words. For each word that doesn't already exist you could increase the counter and use the new value as the unique id.
Lastly, might I suggest you use a HashMap instead. It would allow you to both insert and retrieve words in O(1) time. I am not entirely sure what you are going for, but I think the HashMap might give you more range.
Edit2:
It would be something a little more along these lines. This should help you out.
public static Set<DataPair> getAllWords(String[] tempsArray) {
Set<DataPair> set = new HashSet<>();
for (String row : tempsArray) {
// PARSE YOUR STRING DATA
// the way you were doing it seemed fine but something like this
String[] rowArray = row.split(" ");
String word = row[1];
int id = Integer.parseInt(row[0]);
DataPair pair = new DataPair(word, id);
set.add(pair);
}
return set;
}
class DataPair {
private String word;
private int id;
public DataPair(String word, int id) {
this.word = word;
this.id = id;
}
public boolean equals(Object o) {
if (o instanceof DataPair) {
return ((DataPair) o).word.equals(word) && ((DataPair) o).id == id;
}
return false;
}
}

Parse from List<String> Java

I am attempting to parse the value of the elements in a List declared as thus:
List<String> uniqueList = new ArrayList<String>(dupMap.values());
The values are such as this:
a:1-2
b:3-5
but I want one ArrayList with the first number (i.e. 1, 3) and another with the second (i.e. 2, 5). I have this worked out... Sorta:
String delims= "\t"; String delim2= ":"; String delim3= "-";
String splits2[]; String splits3[]; String splits4[];
Map<String,String> dupMap = new TreeMap<String, String>();
List<String> uniqueList = new ArrayList<String>(dupMap.values());
ArrayList<String> parsed2 = new ArrayList<String>();
ArrayList<String> parsed3 = new ArrayList<String>();
ArrayList<String> parsed3two= new ArrayList<String>();
double uniques = uniqueList.size();
for(int a=0;a<uniques;a++){
//this doesn't work like it would for an ArrayList
splits2 = uniqueList.split(delim2) ;
parsed2.add(splits2[1]);
for(int q=0; q<splits2.length; q++){
String change2 = splits2[q];
if(change2.length()>2){
splits3 = change2.split(delim3);
parsed3.add(splits3[0]);
String change3=splits3[q];
if (change3.length()>2){
splits4 = change3.split(delims);
parsed3two.add(splits4[0]);
}
}
}
}
uniqueList.split does not work however and I don't know if there is a similar function for List. Is there any suggestions?
If you know that all of your data is in the form [something]:[num]-[num], you can use a regular expression like this:
Pattern p = Pattern.compile("^([^:]*):([^-]*)-([^-]*)$");
// I assume this holds all the values:
List<String> uniqueList = new ArrayList<String>(dupMap.values());
for (String src : uniqueList) {
Matcher m = p.matcher(src);
if( m.find() && m.groupCount() >= 3) {
String firstValue = m.group(1); // value to left of :
String secondValue = m.group(2); // value between : and -
String thirdValue = m.group(3); // value after -
// assign to arraylists here
}
}
I didn't actually put the code in to add to the specific ArrayLists because I couldn't quite tell from your code which ArrayList was supposed to hold which value.
Edit
Per Code-Guru's comment, an implementation using String.split() would go something like this:
String pattern = "[:\\-]";
// I assume this holds all the values:
List<String> uniqueList = new ArrayList<String>(dupMap.values());
for (String src : uniqueList) {
String[] parts = src.split(pattern);
if (parts.length == 3) {
String firstValue = parts[1]; // value to left of :
String secondValue = parts[2]; // value between : and -
String thirdValue = parts[3]; // value after -
// assign to arraylists here
}
}
Both approaches are pretty much the same in terms of efficiency.
From what I understand of your question, I would proceed as follows:
for each String in uniqueList
parse the string into a character and two integers (probably using a single call to [String.split()](http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#split(java.lang.String, int))
insert the first integer into an List
insert the second integer into another List
This is in pseudocode. Translating into Java is left as an exercise to the reader.

Categories