Home > Enterprise >  How do I check if two specific words are equally as often in a string (without loops)?
How do I check if two specific words are equally as often in a string (without loops)?

Time:11-05

I am trying to find out if the same amount of "dog" "cat" are in my String. It shall return True if they are equally often in the string and return false if they re not. How can I figure this out 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()));
  • Related