Java Collections-the number of words without repetition - java

I wan to create a method for which we give text(String) as an input argument.
The method will return the number of words without repetition.
For example: "cat, dog, Cat, Bird, monkey"
return value:4
How can I compare each Collections item with each other?
What I already have:
public class WordsCounter {
public static void main(String[] args) {
uniqueWordsCounter("cat, dog, Cat, Bird, monkey");
}
public static void uniqueWordsCounter(String text) {
String processedText = text.toLowerCase().replaceAll(",", "");
String[] words = processedText.split("\\s");
List<String> wordsList = Arrays.asList(words);
}
}

One way is to use the distinct() operation from the stream API:
import java.util.*;
public class WordsCounter {
public static void main(String[] args) {
uniqueWordsCounter("cat, dog, Cat, Bird, monkey");
}
public static void uniqueWordsCounter(String text) {
String[] words = text.toLowerCase().split(",\\s*");
List<String> wordsList = Arrays.asList(words);
System.out.println(wordsList);
System.out.println("Count of distinct elements: "
+ wordsList.stream().distinct().count());
}
}
Example run:
$ java Demo.java
[cat, dog, cat, bird, monkey]
Count of distinct elements: 4
Note splitting on comma followed by optional whitespace instead of your replacing commas and then splitting, to help simplify things.

You can use a set to keep track of all the unique elements present in your string after you separate it using the delimiter ","
In your example, you are keeping cat and Cat as same ( ignoring case ) . Thus, you can use this logic.
public class WordsCounter {
public static void main(String[] args) {
int count = uniqueWordsCounter("cat,dog,Cat,Bird,monkey");
System.out.println(count);
}
public static int uniqueWordsCounter(String text) {
String str[] = text.split(",");
Set<String> set = new HashSet<>() ;
for( String temp : str)
{
if ( !set.contains(temp.toLowerCase()))
{
set.add(temp);
}
}
return set.size();
}
}
and the output is
4

Related

How to remove comma from HashSet String java

I have a HashSet String ['a','b','c']. How can I print the String abc?
My code:
import java.util.*;
public class Main
{
public static void main(String[] args) {
HashSet<Character>h=new HashSet<>();
h.add('a');
h.add('b');
h.add('c');
// if here i am print HashSet element then print
System.out.println(h); //[a,b,c]
// now i HashSet convert in String
String res=h.toString();
// when i try to print String then print [a,b,c]
System.out.println(res); // [a,b,c]
//but i am not interest in this result becuase i wnat to print only abc remove all brackets [] ,and , commas
}
You just have to use String.join() as followed
System.out.println(String.join("",h));
If you are using Java 8 or later then you can use Java Stream API, or Iterable.forEach():
public class HashSetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>(Arrays.asList("a", "b", "c", "d", "e"));
System.out.println("System.out.println(set): " + set);
System.out.print("Using .forEach() method: ");
set.forEach(System.out::print);
System.out.println();
System.out.print("Using Stream API: ");
set.stream().forEach(System.out::print);
System.out.println();
}
}
The output will be:

What is the difference between String[] data and String... data in java [duplicate]

This question already has answers here:
Java varargs method param list vs. array
(6 answers)
Closed 2 years ago.
I have tried with data and data1 variables. It's always calling to String ... data.
So, what is the difference between String[] data and String... data in java.
public class ArrayTest {
public static void main(String[] args) {
ArrayTest arrayTest = new ArrayTest();
// Option one
String[] data = {"A", "B", "C"};
// Option two
String data1 = "A";
arrayTest.test(data);
}
public void test(String[] ... data ) {
System.out.println("---From: String[] ... data---");
for(String[] item: data) {
for(String innerItem : item) {
System.out.println(innerItem);
}
}
}
public void test(String ... data ) {
System.out.println("---From: String ... data---");
for(String item: data) {
System.out.println(item);
}
}
}
In test(String... data) you are passing an array of strings and in test(String[]... data) you are passing an array of arrays of strings. Check the updated code for illustration:
public class ArrayTest {
public static void main(String[] args) {
ArrayTest arrayTest = new ArrayTest();
// Option one
String[] data = { "A", "B", "C" };
// Option two
arrayTest.test(data);
String[] data2 = { "D", "E" };
arrayTest.test(data, data2);
}
public void test(String[]... data) {
System.out.println("---From: String[] ... data---");
for (String[] item : data) {
for (String innerItem : item) {
System.out.println(innerItem);
}
}
}
public void test(String... data) {
System.out.println("---From: String ... data---");
for (String item : data) {
System.out.println(item);
}
}
}
Output:
---From: String ... data---
A
B
C
---From: String[] ... data---
A
B
C
D
E
In the presence of both versions of method signatures, JVM chooses the closest fit and that is why it goes to test(String... data) in case of arrayTest.test(data) while it goes to test(String[]... data) in case of arrayTest.test(data, data2).
The program will still work if you remove the following definition but then JVM will be left with only one choice, which is to go to test(String[]... data) for both the calls.
public void test(String... data) {
System.out.println("---From: String ... data---");
for (String item : data) {
System.out.println(item);
}
}
When using Varargs (T...) arguments are packed into an array which is passed to the method at run time.
You have already answered your question with your own implementation:
For:
1) public void test(String[] ... data) -- data is packed as String[][]
2) public void test(String ... data) -- data is packed as String[]
I strongly recommend the book: Java generics and collections - By Maurice Naftalin
method(String... s) // fine
method(int i , String... s) // fine
method(String... s,int i) // not fine , ...s should be last or only parameter
method(String[] s) // fine
method(int i , String[] s) // fine
method(String[] s,int i) // fine
method(String s[]) // fine
method(String s...) // not fine can't put dot's after variable name
method(int[] i , String[] s) //fine
method(int... i , String...) // not fine, only one var arg is allowed
method(String... s) // takes any number of comma separated string also the array of String
method(String[] s) //only takes array of String but not comma separated string
At last -> (String[]... s) is equivalant to (String[][] s)
String ... will read a single sentence with multiple words.
String[] ... will read a paragraph of multiple sentences.

sorting an array List [duplicate]

This question already has answers here:
How to sort an ArrayList in Java [duplicate]
(3 answers)
Closed 4 years ago.
i am trying to sort an list array that has Strings that contain Integers and letters but when i do it the regular way i get some wierd output:
relevant code:
List<String> words = new ArrayList<>();
words.add("9 hello");
words.add("98 food");
words.add("105 cat");
words.add("2514 human");
words.add("3 pencil");
words.sort(Comparator.reverseOrder());
i am expecting :
"2514 human"
"105 cat"
"98 food"
"9 hello"
"3 pencil"
but i am getting something like this:
"98 food"
"9 hello"
"3 pencil"
"2514 human"
"105 cat"
any suggestions?
I think you should create a class to represent the elements in the list.
For instance:
public class WordCount {
public static final Comparator<WordCount> BY_COUNT;
private static final Pattern PATTERN
= Pattern.compile("\\s*([0-9]+)\\s+(.*)");
public final int count;
public final String word;
public static WordCount parse(String s) {
Matcher matcher = PATTERN.matcher(s);
if (!matcher.matches()) {
throw new IllegalArgumentException("Syntax error: " + s);
}
return new WordCount(
Integer.parseInt(matcher.group(1)), matcher.group(2));
}
public WordCount(int count, String word) {
this.count = count;
this.word = word;
}
#Override
public String toString() {
return count + " " + word;
}
static {
BY_COUNT = (WordCount o1, WordCount o2) -> {
int r = Integer.compare(o1.count, o2.count);
if (r == 0) {
r = o1.word.compareTo(o2.word);
}
return r;
};
}
}
Your code would then become:
List<WordCount> words = new ArrayList<>();
words.add(WordCount.parse("9 hello"));
words.add(WordCount.parse("98 food"));
words.add(WordCount.parse("105 cat"));
words.add(WordCount.parse("2514 human"));
words.add(WordCount.parse("3 pencil"));
words.sort(WordCount.BY_COUNT.reversed());
words.forEach((wc) -> {
System.out.println(wc);
});
With the following result:
2514 human
105 cat
98 food
9 hello
3 pencil
Use comporator to solve your problem like this
Add this code inside you class
private static Comparator<String> ORDER_MYLIST = new Comparator<String>() {
public int compare(String d, String d1) {
int first = Integer.parseInt(d.split(" ")[0]);//since you have space
int second = Integer.parseInt(d1.split(" ")[0]);
return second - first;//change the order if you want
}
};
Add this code in your calling function
Collections.sort(words, ORDER_MYLIST);
Output:
[2514 human, 105 cat, 98 food, 9 hello, 3 pencil]
Will be as you expect.
This link will give you better understanding on how comporator works
https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html
You need to have a custom comparator to satisfy your requirement.
Java 8 solution:
List<String> words = new ArrayList<>();
words.add("9 hello");
words.add("98 food");
words.add("105 cat");
words.add("2514 human");
words.add("3 pencil");
// Sort the existing list
words.sort(Comparator.comparing(s -> Integer.parseInt(s.split(" ")[0]), Comparator.reverseOrder()));
// To create new sorted list
List<String> sortedWords = words.stream()
.sorted(Comparator.comparing(s -> Integer.parseInt(s.split(" ")[0]), Comparator.reverseOrder()))
.collect(Collectors.toList());
What you've got is exactly lexicographical order because not numbers are compared but their digits alphabetically.
If you want other behavior then you should consider implementing your own Comparator in which you'll parse the numbers.

How to find the missing elements in a sequence?

I have a string arraylist under that i need to pass 22184 elements from ["AA00001", "AA00005" ,"AA00003" ----- "ZZ00678"] and i need to generate the sequence elements which are not present in the list. I have written code for that and for less inputs it is generating the required output. But when i am adding 22184 elements and want to generate 200 unique ids which are not present in the arraylist i am getting error as
The code of method main(String[]) is exceeding the 65535 bytes limit
Can someone please help ?
import java.util.ArrayList;
public class GenerateIds
{
private static ArrayList<String> ids = new ArrayList<>();
static int n=50; //no of Ids u want to generate
static int completed =0;
static char ID[] = new char[7];
public static void main(String[] args)
{
ids.add("AA00001");
ids.add("AA00004");
ids.add("AA00007");
generateIds(0);
for(String id : ids)
{
System.out.println(id);
}
}
private static void generateIds(int i)
{
if(n!=completed)
{
if(i<2)
{
for(char c ='A';c<'Z';c++)
{
ID[i]=c;
generateIds(i+1);
}
}
else if(i>=2 && i<7)
{
for(char c ='0';c<='9';c++)
{
ID[i]=c;
generateIds(i+1);
}
}else if(i==7)
{
String id = String.valueOf(ID);
if(!ids.contains(id))
{
ids.add(id);
completed++;
}
}
}
}
}
You can put your id's in a text file. Then use something like.
List<String> ids = Files.readAllLines(Paths.get("ids.txt"));
In java a methods can't have more than 65535 bytes.
The main method is becoming too large since you are doing all the adds inline:
ids.add("AA00001");
ids.add("AA00004");
ids.add("AA00007");
...
This will make the main method too long. What you can do to solve this (and to find the missing elements) is putting all the String values in a List and loop over it to find the missing elements:
public void findMissingElements() {
List<String> missingIds = allPossibleIds.stream()
.filter(isMissingIn(existingIds))
.collect(toList());
//do something with the missingIds...
}
As other readers such as matt suggested, you can e.g. put all the Strings in a file and read the file.
I wrote a small example to show how it would all work together. I rewrote your generateIds method with jOOλ to generate all the possible ids and renamed it to allPossibleIds (however your recursive method would work too). I limited the ids to a 3 size digit number to limit the search time as an example.
public class FindMissingIdsTest {
private List<String> allPossibleIds;
private List<String> existingIds;
#Before
public void setup() throws IOException {
allPossibleIds = allPossibleIds();
existingIds = retrieveIdsFromSubSystem();
}
#Test
public void findMissingElements() {
List<String> missingIds = allPossibleIds.stream()
.filter(isMissingIn(existingIds))
.collect(toList());
}
private Predicate<String> isMissingIn(List<String> existingIds) {
return possibleId -> !existingIds.contains(possibleId);
}
public List<String> allPossibleIds(){
List<String> alphabet = Seq.rangeClosed('A', 'Z').map(Object::toString).toList();
List<String> letterCombinations = Seq.seq(alphabet).crossJoin(Seq.seq(alphabet)).map(t -> t.v1 + t.v2).toList();
List<String> numbericParts = IntStream.range(0, 1000)
.mapToObj(i -> String.format("%03d", i))
.collect(toList());
return Seq.seq(letterCombinations).crossJoin(Seq.seq(numbericParts)).map(t -> t.v1 + t.v2).toList();
}
public List<String> retrieveIdsFromSubSystem() throws IOException {
return Files.readAllLines(Paths.get("ids.txt"));
}
}
To change to 5 digits again you can just change the 1000 to 100000 and the %03d to %05d.
If you can order the list, you could probably find a faster and better algorithm. It all depends on the situation. e.g. if you have an ordered list, you could build up the stream of all the ids, iterate over it and follow in the existing list with a pointer instead of always doing a resource consuming contains().

How to skip a particular string during string Joining in Java?

The source code I have uploaded it will join some strings value in a one line. I want a way that I can able to skip a particular string in time of string joining. Here i have stored the strings "This","is","a","test." in a string array. I want that in time of joining a particular string will be skipped. Like I want to skip "a". How can I able to do in Java? I want a generalized way that I will able to apply for any strings.
import java.util.StringJoiner;
public class Test_Joiner_for_seatPlan
{
public static void main(String[] args)
{
StringJoiner joinString = new StringJoiner( " ");
String[] testStringArray = {"This","is","a","test."};
String joinedString = null;
for(String s : testStringArray)
{
joinString.add(s);
}
joinedString = joinString.toString();
System.out.println("After Joining the String:\n"+joinedString);
}
}
Try with not equal condition with string. but its not feasible as its check everytime a value.
for(String s : testStringArray)
{
if(!s.equals("a")){
joinString.add(s);
}
}
If you have a list of values like a,b,c than you can do like this:
Set<String> exclude = new HashSet<String>(Arrays.asList("a","b","c"));
for(String s : testStringArray)
{
if(!exclude.contains(s)){
joinString.add(s);
}
}
Use Split method of string. It returns array. combine each of them to get the string.
for (String retval: Str.split("a")){
System.out.println(retval);
}
You can do it like this:
Code:
for(String s : testStringArray){
if(!s.equals("a")){ // replace 'a' with the required character or word you want to ignore
joinString.add(s);
}
}
One possible solution is to provide a Map or a List in which you store the String values that should get excluded in your join. Here is an example using a Map.
public static void main(String[] args) {
String[] testStringArray = {"This","is","a","test."};
Map<String, String> excludedStrings = createExcludingMap("a");
System.out.println("After Joining the String:\n" + join(testStringArray, excludedStrings));
}
private static String join(String[] inputData, Map<String, String> excludedStrings){
StringJoiner joinString = new StringJoiner( " ");
String joinedString = null;
for(String s : inputData)
{
if(excludedStrings.get(s) == null) // IF this return null, the String is not part of the Strings to be excluded, hence join the string
joinString.add(s);
}
joinedString = joinString.toString();
return joinString.toString();
}
private static Map<String, String> createExcludingMap(String... values) {
Map<String, String> output = new HashMap<>();
for(String s : values) { // Add each value to the map, with s as key
output.put(s, s);
}
return output;
}
output :/
After Joining the String:
This is test.
The StringJoiner is a utility class that was written specifically to be used with the new Java8 Stream functionality. The documentation of StringJoiner also refers to the Collectors.joining method. It creates the StringJoiner, and wraps it in an object suitable to pass to Stream.collect, actually a Collector.
As part of the Stream API we now also have direct support for filters, it is just a matter of employing the fluent API (fluent because we keep adding .something(...)) to add the .filter method.
You can use it as you did in your answer, but I would suggest doing it as follows:
import static java.util.stream.Collectors.joining;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class App {
public static String joinString(String [] sa,Predicate<String> filter) {
return Stream.of(sa).filter(filter).collect(joining(" "));
}
public static void main(String[] args) {
String[] testStringArray = new String [] {"This","is","a","test."};
System.out.println(joinString(testStringArray,(s)->!s.equals("a")));
}
}
I have deliberately broken it up by defining an extra method, so you can see the type of the filter passed along, exposing the Predicate. This would also make your function a little more generic making it work as you stated: 'I want a generalized way that I will able to apply for any strings'.
However if the Stream api is flexible enough that I do not see any need to abstract your own API for it. I suggest using it as-is:
import static java.util.stream.Collectors.joining;
import java.util.stream.Stream;
public class App {
public static void main(String[] args) {
System.out.println(
Stream
.of(new String [] {"This","is","a","test."})
.filter((s)->!s.equals("a"))
.collect(joining(" "))
);
}
}
I could have written most of it on a single line, but I like to break it up for readability.

Categories

Resources