Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Tesseraction
Apr 5, 2009

It filters out empty strings - word.trim() removes whitespace, so it returns either a full word with no spaces, or if there was only blank spaces, trim() returns the empty string "".

Basically the string version of "!= null"

Adbot
ADBOT LOVES YOU

samcarsten
Sep 13, 2022

by vyelkin

Tesseraction posted:

It filters out empty strings - word.trim() removes whitespace, so it returns either a full word with no spaces, or if there was only blank spaces, trim() returns the empty string "".

Basically the string version of "!= null"

ok, that makes sense. I'm looking at stream commands, and I'm not sure what equates to an "if" statement.

Tesseraction
Apr 5, 2009

Going by the example provided in the doc I linked:

code:
List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());
Looks like .filter() fits the bill, using a lamba to say match t where t.getType() returns the value of Transaction.GROCERY.

(As an aside, I'm assuming you recognise from the capitalisation that Transaction.GROCERY is an enumeration.)

samcarsten
Sep 13, 2022

by vyelkin

Tesseraction posted:

Going by the example provided in the doc I linked:

code:
List<Integer> transactionsIds = 
    transactions.stream()
                .filter(t -> t.getType() == Transaction.GROCERY)
                .sorted(comparing(Transaction::getValue).reversed())
                .map(Transaction::getId)
                .collect(toList());
Looks like .filter() fits the bill, using a lamba to say match t where t.getType() returns the value of Transaction.GROCERY.

(As an aside, I'm assuming you recognise from the capitalisation that Transaction.GROCERY is an enumeration.)

I thought enumerations were not able to be created, but inbuilt? Where does GROCERY come from?

samcarsten
Sep 13, 2022

by vyelkin
Hmm, added filter, but got an error.

The method filter((<no type> word) -> {}) is undefined for the type String

my code is:

document.stream().peek(word->word.toLowerCase().filter(word->word.equals(word.trim)));

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

I thought enumerations were not able to be created, but inbuilt? Where does GROCERY come from?

This is different from an enumerable like an Array. It's usually referred to as an Enum to keep confusion to a minimum. Documentation is here.

Tesseraction
Apr 5, 2009

samcarsten posted:

Hmm, added filter, but got an error.

The method filter((<no type> word) -> {}) is undefined for the type String

my code is:

document.stream().peek(word->word.toLowerCase().filter(word->word.equals(word.trim)));

Hmm, I don't think this captures the spirit of what the teacher wants you to do. I assume the goal is to count the frequency of words appearing?

To apply a function to every element in the stream you want to use map(), and then filter doesn't get you a wordcount, it merely filters out all elements that don't match your predicate. It would probably be better to create a wrapper function for map() that

1) performs the toLowerCase() function (and if necessary a trim() and filtering out of "")

2) then interacts with wordFrequency

samcarsten
Sep 13, 2022

by vyelkin
hmm, trying that, but still getting an error.

document.stream().peek(word->word.toLowerCase().peek(word->word.trim))

The method peek((<no type> word) -> {}) is undefined for the type String

Tesseraction
Apr 5, 2009

Peek appears to more be a debugging function for seeing what the stream looks like at a certain point in operation, at least according to the documentation https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#peek-java.util.function.Consumer-

Naar
Aug 19, 2003

The Time of the Eye is now
Fun Shoe
You practically never need to use peek for anything. It will only evaluate the function's side effects, nothing permanent will happen. The key bits for your Stream are map, filter and groupingBy.

samcarsten
Sep 13, 2022

by vyelkin

Tesseraction posted:

Hmm, I don't think this captures the spirit of what the teacher wants you to do. I assume the goal is to count the frequency of words appearing?

To apply a function to every element in the stream you want to use map(), and then filter doesn't get you a wordcount, it merely filters out all elements that don't match your predicate. It would probably be better to create a wrapper function for map() that

1) performs the toLowerCase() function (and if necessary a trim() and filtering out of "")

2) then interacts with wordFrequency

Right, but what commands do I use to do that?

samcarsten
Sep 13, 2022

by vyelkin
Same error.

document.stream().filter(word->word.toLowerCase().filter(word->word.trim));

The method filter((<no type> word) -> {}) is undefined for the type String

hooah
Feb 6, 2006
WTF?

samcarsten posted:

Same error.

document.stream().filter(word->word.toLowerCase().filter(word->word.trim));

The method filter((<no type> word) -> {}) is undefined for the type String

You're not closing your parentheses in the right place with your stream operations.

samcarsten
Sep 13, 2022

by vyelkin
New error.

document.stream().filter(word->word.toLowerCase()).filter(word->word.trim());

Type mismatch: cannot convert from String to boolean

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

New error.

document.stream().filter(word->word.toLowerCase()).filter(word->word.trim());

Type mismatch: cannot convert from String to boolean
The issue is with .filter(word->word.toLowerCase()). The filter command does what it says, filters stuff out based on a logical statement. Because of this, it expects the function inside it to return a boolean. In your code, toLowerCase() returns a string. I assume you don't actually want to filter there, but rather call the toLowerCase() method for all strings. Can you find a command more appropriate for that in the documentation.

Hint: Having the documentation at the ready is like having a map handy when you want to get to a specific destination.

samcarsten
Sep 13, 2022

by vyelkin
cool, so replacing it with map worked, but I'm not sure of the lambda statement that is equivalent to:

!"".equals(word.trim)

Tesseraction
Apr 5, 2009

Something along the lines of t -> !"".equals(t.trim())

Lamba functions are basically a "find/replace" for whatever is on the left of the arrow. For everything in the list given, call it (in this case) t and then apply everything to the right of the arrow.

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

cool, so replacing it with map worked, but I'm not sure of the lambda statement that is equivalent to:

!"".equals(word.trim)

It's not really. Honestly, I'm not sure why the filter works in this case. But assuming you want to filter out words consisting of only whitespace, the filter should actually compare it to an empty string. So you could use the bit from the loop directly ( filter(word -> !"".equals(word.trim())) ), but since that looks ugly as gently caress to me, I'd rather you do filter(word -> !word.trim().equals("")).

Tesseraction
Apr 5, 2009

I suspect it was deliberately put that way to confuse the students, or at least give them pause to think what it means.

samcarsten
Sep 13, 2022

by vyelkin
ok, so my current statement is:

.map((Integer cnt) -> cnt.wordFrequency.get(word))

but it's giving me the error:

Type mismatch: cannot convert from Function<Integer,? extends R> to Function<? super String,? extends R>

Tesseraction
Apr 5, 2009

That's an interesting lambda.

When .map() is called the only thing it's aware of is the stream, anything inside the brackets has to be defined in terms the stream. Currently you're telling it to parse through the stream and as it does so, declare an integer called cnt but don't instantiate it, then push that into a lambda function... and ask for that integer to then access a wordFrequency (which isn't part of the Integer class) and from that wordFrequency call the get() function.

I think you might benefit from learning the principles of lambda calculus (at least to the extent it's used in Java / other languages).

The idea is say you have a array [1,2,3,4] that applying "lambda a -> a * a" will output [1,4,9,16] because for each element in the array, it is now called a, and on the other side of the arrow, the function says that you should return the value of a * a.

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

ok, so my current statement is:

.map((Integer cnt) -> cnt.wordFrequency.get(word))

but it's giving me the error:

Type mismatch: cannot convert from Function<Integer,? extends R> to Function<? super String,? extends R>

Honestly, I think you need to go back a bit and try and understand the syntax before you write any more code. A stream is basically a pipeline of commands. You usually start from a list, then add commands which either perform a function for all members of the list, filter stuff out etc. The stuff you've been doing to this point. So stuff like..

list.map(variable -> variable.doStuff()).filter(variable -> variable > tooSmall) etc.

The part that you're trying to replicate is this...

code:
if (!"".equals(word.trim())) {
						Integer cnt = wordFrequency.get(word);
						if (cnt == null) {
							wordFrequency.put(word, 1);
						} else {
							int icnt = cnt + 1;
							wordFrequency.put(word, icnt);
						}
					}
Where Integer cnt = wordFrequency.get(word) is assigning the a value to an integer variable called cnt using the get-method of a variable called wordFrequency. The code you wrote tries to call the member wordFrequency of a variable called cnt, which makes no sense.

What you want to do after the filter is something called a collect. You can look it up in the documentation. But the syntax for that command is very fiddly, so you should definitely look up some practical examples for it. You can even google a word frequency example which does exactly what is wanted in your homework. But because the syntax is fiddly, and you don't have a good grasp of java syntax yet, I'd really take a breather, find a syntax cheat sheet and take your time with it, so you know exactly what you're trying to do when you write code.

Edit: Oh, and being able to read the documentation is a skill of it's own. To get better at it, you probably want to look up some methods that are familiar to you and that you have a good grasp of and see how the documentation presents those.

Kuule hain nussivan fucked around with this message at 20:53 on Nov 21, 2022

samcarsten
Sep 13, 2022

by vyelkin

Kuule hain nussivan posted:

Honestly, I think you need to go back a bit and try and understand the syntax before you write any more code. A stream is basically a pipeline of commands. You usually start from a list, then add commands which either perform a function for all members of the list, filter stuff out etc. The stuff you've been doing to this point. So stuff like..

list.map(variable -> variable.doStuff()).filter(variable -> variable > tooSmall) etc.

The part that you're trying to replicate is this...

code:
if (!"".equals(word.trim())) {
						Integer cnt = wordFrequency.get(word);
						if (cnt == null) {
							wordFrequency.put(word, 1);
						} else {
							int icnt = cnt + 1;
							wordFrequency.put(word, icnt);
						}
					}
Where Integer cnt = wordFrequency.get(word) is assigning the a value to an integer variable called cnt using the get-method of a variable called wordFrequency. The code you wrote tries to call the member wordFrequency of a variable called cnt, which makes no sense.

What you want to do after the filter is something called a collect. You can look it up in the documentation. But the syntax for that command is very fiddly, so you should definitely look up some practical examples for it. You can even google a word frequency example which does exactly what is wanted in your homework. But because the syntax is fiddly, and you don't have a good grasp of java syntax yet, I'd really take a breather, find a syntax cheat sheet and take your time with it, so you know exactly what you're trying to do when you write code.

Edit: Oh, and being able to read the documentation is a skill of it's own. To get better at it, you probably want to look up some methods that are familiar to you and that you have a good grasp of and see how the documentation presents those.

Right, but collect is a terminal operation and there's still more to go.

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

Right, but collect is a terminal operation and there's still more to go.

Is there? If you break the loop into bits, it's...

1. Make lowercase
2. Filter out empties
3. Count frequencies

samcarsten
Sep 13, 2022

by vyelkin

Kuule hain nussivan posted:

Is there? If you break the loop into bits, it's...

1. Make lowercase
2. Filter out empties
3. Count frequencies

Ugh, this is all so confusing. So I only need one filter statement, despite the inner loop?

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

Ugh, this is all so confusing. So I only need one filter statement, despite the inner loop?

Yup, eveything after the first if, the trim check, is handled by the collect.

samcarsten
Sep 13, 2022

by vyelkin
Ok, I think I am close, but there is one more error. My code is:

wordFrequency = document.stream().map(word->word.toLowerCase()).map(word->word.trim()).filter(word -> !"".equals(word.trim())).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

The error is:

Type mismatch: cannot convert from Map<String,Long> to Map<String,Integer>

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

Ok, I think I am close, but there is one more error. My code is:

wordFrequency = document.stream().map(word->word.toLowerCase()).map(word->word.trim()).filter(word -> !"".equals(word.trim())).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

The error is:

Type mismatch: cannot convert from Map<String,Long> to Map<String,Integer>

Not bad. The second map is superfluous and can be removed, since you do the trim in the filter. Try casting (changing the type) of the count to Integer by doing (Integer) Collectors.counting().

samcarsten
Sep 13, 2022

by vyelkin

Kuule hain nussivan posted:

Not bad. The second map is superfluous and can be removed, since you do the trim in the filter. Try casting (changing the type) of the count to Integer by doing (Integer) Collectors.counting().

Cannot cast from Collector<Object,capture#1-of ?,Long> to Integer

Kuule hain nussivan
Nov 27, 2008

samcarsten posted:

Cannot cast from Collector<Object,capture#1-of ?,Long> to Integer
Hmmm, you need to get Collectors.counting to return (or convert) the result to Integer. I'm off to bed, so give it a google. I'm sure Tesseraction will be along to help you soon as well.

Tesseraction
Apr 5, 2009

God these polymorphic parameterisations. Back in my day everything was an object and you prayed it worked.

Look at the API it shows counting() is static <T> Collector<T,?,Long>

So maybe Collectors<?,?,Integer>.counting()?

If that doesn't work I'll sleep on it as well, since you say you've got two weeks for this bastard. I've not messed around with generics in Java and Monday night is not the best time to wrap my head around it.

samcarsten
Sep 13, 2022

by vyelkin

Tesseraction posted:

God these polymorphic parameterisations. Back in my day everything was an object and you prayed it worked.

Look at the API it shows counting() is static <T> Collector<T,?,Long>

So maybe Collectors<?,?,Integer>.counting()?

If that doesn't work I'll sleep on it as well, since you say you've got two weeks for this bastard. I've not messed around with generics in Java and Monday night is not the best time to wrap my head around it.

Okay, did that, but its giving me an error indication on the comma between function and collectors.

wordFrequency = document.stream().map(word->word.toLowerCase()).filter(word -> !"".equals(word.trim())).collect(Collectors.groupingBy(Function.identity(), Collectors<?,?,Integer>.counting()));

Tesseraction
Apr 5, 2009

Yeah I tried throwing it in Eclipse and it's yelling at me about how it's not actually generic. I'll look at this properly tomorrow.

ada shatan
Oct 20, 2004

that'll do pig, that'll do

Tesseraction posted:

Yeah I tried throwing it in Eclipse and it's yelling at me about how it's not actually generic. I'll look at this properly tomorrow.


Maybe it's just me being optimistic about this class and the intended lesson, but I suspect we may be over-complicating the solution by getting too deep into generics.

How is wordFrequency defined? From looking at the error I'd speculate it's something along the lines of Map<String, Integer>, right? So the first question I'd ask (since we see that the issue is the Map wants an Integer but is getting a Long) is can we change the definition of wordFrequency so that it supports the simple solution of leveraging Collectors.counting()? If we can't what other methods does the Collectors class have that we may be able to leverage in order to produce an Integer in the returned Collector?

Kilson
Jan 16, 2003

I EAT LITTLE CHILDREN FOR BREAKFAST !!11!!1!!!!111!

Tesseraction posted:

God these polymorphic parameterisations. Back in my day everything was an object and you prayed it worked.

Look at the API it shows counting() is static <T> Collector<T,?,Long>

So maybe Collectors<?,?,Integer>.counting()?

If that doesn't work I'll sleep on it as well, since you say you've got two weeks for this bastard. I've not messed around with generics in Java and Monday night is not the best time to wrap my head around it.

The only way I could get this to work easily was to use:

Java code:

Collectors.groupingBy(Function.identity(),
    Collectors.collectingAndThen(
        Collectors.counting(), Long::intValue)))

Tesseraction
Apr 5, 2009

ada shatan posted:

Maybe it's just me being optimistic about this class and the intended lesson, but I suspect we may be over-complicating the solution by getting too deep into generics.

How is wordFrequency defined? From looking at the error I'd speculate it's something along the lines of Map<String, Integer>, right? So the first question I'd ask (since we see that the issue is the Map wants an Integer but is getting a Long) is can we change the definition of wordFrequency so that it supports the simple solution of leveraging Collectors.counting()? If we can't what other methods does the Collectors class have that we may be able to leverage in order to produce an Integer in the returned Collector?

Yeah, you're right that for homework this feels overly complicated. That might be why they apparently get two weeks for this one, but could well be we're missing the forest. Might be worth samcarsten showing us the full homework brief including document.

Kilson posted:

The only way I could get this to work easily was to use:

Java code:
Collectors.groupingBy(Function.identity(),
    Collectors.collectingAndThen(
        Collectors.counting(), Long::intValue)))

Ooh, nice.

samcarsten
Sep 13, 2022

by vyelkin
The full home work brief is less than a paragraph.

Individual Term Project - Frequent Words & Spelling Analysis
Modify the program SCFWStreamsFX.java to remove the loops and replace them with stream statements in the btMostFrequentWords.setOnAction() and btMisspelledWordCount.setOnAction() methods. Note that "Most Frequent Words" feature, as given, works correctly; you can use the given version to test against your modified version. Same with the "MIsspelled Word Count" feature.

ada shatan
Oct 20, 2004

that'll do pig, that'll do

samcarsten posted:

The full home work brief is less than a paragraph.

Individual Term Project - Frequent Words & Spelling Analysis
Modify the program SCFWStreamsFX.java to remove the loops and replace them with stream statements in the btMostFrequentWords.setOnAction() and btMisspelledWordCount.setOnAction() methods. Note that "Most Frequent Words" feature, as given, works correctly; you can use the given version to test against your modified version. Same with the "MIsspelled Word Count" feature.

Can you share the source for SCFWStreamsFX.java?

samcarsten
Sep 13, 2022

by vyelkin

ada shatan posted:

Can you share the source for SCFWStreamsFX.java?

sure. let me throw it on google drive.

https://drive.google.com/file/d/1hi6k0AxSMG-nJ-odpJ0uwObswwCPgHBH/view?usp=share_link

Adbot
ADBOT LOVES YOU

ada shatan
Oct 20, 2004

that'll do pig, that'll do

The relevant file is here: https://controlc.com/1d390e17
password is "goonhomework"

It looks like you'd be well within the guidelines of the assignment to just change the map to use a Long, but if that isn't your intent Kilson's solution looks great. I'm sure myself and others would feel a lot more comfortable if you explained how Kilson's solution works before you hand it in as your own, but you do what works for you.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply