I am trying to find out if there is the same number of occurrences "dog"
and "cat" are in the given String
.
It should return true
if they are equal, or false
otherwise. How can I find out this without while
, for
etc. loops?
This is my current process
class Main {
public static boolean catsDogs(String s) {
String cat = "cat";
String dog = "dog";
if (s.contains(cat) && s.contains(dog)) {
return true;
}
return false;
}
public static void main(String[] args) {
boolean r = catsDogs("catdog");
System.out.println(r); // => true
System.out.println(catsDogs("catcat")); // => false
System.out.println(catsDogs("1cat1cadodog")); // => true
}
}
CodePudding user response:
With java9 the regex matcher has a count method:
public static boolean catsDogs(String s) {
Pattern pCat = Pattern.compile("cat");
Pattern pDog = Pattern.compile("dog");
Matcher mCat = pCat.matcher(s);
Matcher mDog = pDog.matcher(s);
return (mCat.results().count() == mDog.results().count());
}
CodePudding user response:
You can use the following example by replacing the string (in case you don't want the split to be placed) :
public static boolean catsDogs(String s) {
return count(s,"cat") == count(s,"dog");
}
public static int count(String s, String catOrDog) {
return (s.length() - s.replace(catOrDog, "").length()) / catOrDog.length();
}
public static void main(String[] args) {
boolean r = catsDogs("catdog");
System.out.println(r); // => true
System.out.println(catsDogs("catcat")); // => false
System.out.println(catsDogs("1cat1cadodog")); // => true
}
CodePudding user response:
Here's a couple of single-line solutions based on Java 9 Matcher.result()
which produces a stream of MatchResult
corresponding to each matching subsequence in the given string.
We can also make this method more versatile by providing a pair of regular expressions as arguments instead of hard-coding them.
teeing() summingInt()
We can turn the stream of MatchResesult
into a stream of strings by generating matching groups. And collect the data using collector teeing()
expecting as its arguments two downstream collectors and a function producing the result based on the values returned by each collector.
public static boolean hasSameFrequency(String str,
String regex1,
String regex2) {
return Pattern.compile(regex1 "|" regex2).matcher(str).results()
.map(MatchResult::group)
.collect(Collectors.teeing(
Collectors.summingInt(group -> group.matches(regex1) ? 1 : 0),
Collectors.summingInt(group -> group.matches(regex2) ? 1 : 0),
Objects::equals
));
}
collectingAndThen() partitioningBy()
Similarly, we can use a combination of collectors collectingAndThen()
and partitioningBy()
.
The downside of this approach in comparison to the one introduced above is that partitioningBy()
materializes stream elements as the values of the map (meanwhile we're interested only their quantity), but it performs fewer comparisons.
public static boolean hasSameFrequency(String str,
String regex1,
String regex2) {
return Pattern.compile(regex1 "|" regex2).matcher(str).results()
.map(MatchResult::group)
.collect(Collectors.collectingAndThen(
Collectors.partitioningBy(group -> group.matches(regex1)),
map -> map.get(true).size() == map.get(false).size()
));
}
CodePudding user response:
here is what I did for my yugioh! project. I have a deck (list of cards), each card has a string name. I can only have max 3 copies of a card. To check that I used a map between the name of the card and how many times it appeard. you can maybe use and modify what needed (your string instead of deck...). Check also the stream interface.
//count each card occurrences
Map<String,Long> occurrenceMap =deck.stream().collect(Collectors.groupingBy(card -> card.getName(),Collectors.counting()));