1

I have a class that counts the average number of words in a sentence using Lambdas in java. The problem that I'm having is that if corp is null or is empty I need to return 0. Currently I am getting NaN if corp is either null or empty. The rest of my code does what it should, but I cannot figure this part out.

public class AverageNumberOfWordsPerSentence extends TextMetric<Double> {
@Override
public Double apply(final Corpus corp) {
    Sentences sentences = new Sentences();
    List<String> sentenceList = sentences.apply(corp);

    LongSummaryStatistics lss = corp.texts().stream()
                                    .map(blob -> blob.text())
                                    .flatMap(string -> stream
                                    (string.split("\\W+")))
                                    .filter(string -> !string.isEmpty())
                                    .mapToLong(String::length)
                                    .summaryStatistics();                                   
                                    return (double)lss.getCount() / 
                                                   sentenceList.size();
}
Zong
  • 6,160
  • 5
  • 32
  • 46
ObiJuanKanobe
  • 45
  • 1
  • 6

3 Answers3

1

Change the return statement to:

return sentenceList.isEmpty() ? 0.0 : (double)lss.getCount() / sentenceList.size();

And then hope that whoever told you “not to use control structures” will accept it. Strictly speaking, the ?: operator is a control structure, but it doesn’t have a keyword like if or while.

Roland Illig
  • 40,703
  • 10
  • 88
  • 121
0

If I've got you right, then you need to use java.util.Optional:

class AverageNumberOfWordsPerSentence {
    public Double apply(final Corpus corp) {
        return Optional.of(corp).map(corp -> {
            Sentences sentences = new Sentences();
            List<String> sentenceList = sentences.apply(corp);

            LongSummaryStatistics lss = corp.texts().stream()
                    .map(blob -> blob.text())
                    .flatMap(string -> stream
                            (string.split("\\W+")))
                    .filter(string -> !string.isEmpty())
                    .mapToLong(String::length)
                    .summaryStatistics();
            return (double) lss.getCount() /
                    sentenceList.size();
        }).orElse(0);
    }

}

`

nikelin
  • 61
  • 4
0

From the OP's comment,

Corpus corpus = new Corpus("King", text); So if the string where king is is empty or null then I have to return 0.

it appears that there needs to be some conditional logic that bypasses the stream if a member of Corpus is null or empty. The OP didn't say what the name of the property that holds "King" is, so I'll assume it is getKing() for now.

Like what @nikelin posted, Optional will help you here. Using Optional.filter() you can branch without using control structors. For example, you could do this to test to see if the "king" value is there and if it is null or an empty string, return 0, otherwise get the text metrics:

return Optional.of(corp)
     .filter(c -> c.getKing() != null && !c.getKing().isEmpty()) // skip to the orElse() if it is null or empty)
     .map(c -> c.texts())  // or .map(Corpus::texts)
     .map(t -> t.stream()...blah blah get the word count...)
     .map(count -> (double) count / sentences) 
     .orElse(0.0)

Any sequence of successive .map() operations can be combined into one, your choice.

If the initial Optional.filter finds that your "king" property is not null or empty, the stream operation the stream operation proceeds, getting the texts and calculating the word count as you specified already. It then maps the word count to sentenceCount/wordCount and returns that, but if your king property is null, the filter will leave the Optional empty, the map operations will be skipped, and the value in orElse(0.0) will be returned instead.

Hank D
  • 6,271
  • 2
  • 26
  • 35