java
package edu.cmu.cs.cs214.rec14;
import java.io.*;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamPractice {
/** 0. Returns the number of lines in file. (an example) */
public static int lineCountRegular(String fileName) throws IOException {
int result = 0;
try (Scanner sc = new Scanner(new File(fileName))) {
while(sc.hasNextLine()) {
result++;
sc.nextLine();
}
}
return result;
}
/** 0. This solution is an example solution for #0. */
public static int lineCountStream(String fileName) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(fileName))) {
return (int) lines.count();
}
}
/** Returns whether an input string is a palindrome. This helper
* function will be useful for the next method.
*/
private static boolean isPalindrome(String s) {
int length = s.length();
for (int i = 0, j = length - 1; i < length/2; i++, j--)
if (s.charAt(i) != s.charAt(j))
return false;
return true;
}
/** 1. Returns palindromes in word list in original order.
*
* HINT:
*
* You can filter the contents of a stream:
* https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#filter-java.util.function.Predicate-
*
* You can also turn a stream into a Collection using Collectors
* https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
*/
public static List<String> palindromesRegular(String wordListFileName) throws IOException {
List<String> result = new ArrayList<>();
try (Scanner sc = new Scanner(new File(wordListFileName))) {
String line;
while (sc.hasNextLine()) {
line = sc.nextLine();
if (isPalindrome(line))
result.add(line);
}
}
return result;
}
/** 1. Returns palindromes in word list in original order. */
public static List<String> palindromesStream(String wordListFileName) throws IOException {
// TODO: Implement me, matching the above behavior but using Streams.
try (Stream<String> lines = Files.lines(Paths.get(wordListFileName))) {
return lines.filter(s -> isPalindrome(s)).collect(Collectors.toList());
}
}
/** 2. Returns the number of palindromes in word list. */
public static int palindromeCountRegular(String wordListFileName) throws IOException {
int result = 0;
try (Scanner sc = new Scanner(new File(wordListFileName))) {
String line;
while (sc.hasNextLine()) {
line = sc.nextLine();
if (isPalindrome(line)) {
result++;
}
}
}
return result;
}
/** 2. Returns the number of palindromes in word list. */
public static int palindromeCountStream(String wordListFileName) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(wordListFileName))) {
return (int)lines.filter(s -> isPalindrome(s)).count();
}
}
/** 3. Returns the longest palindrome in word list.
* HINT:
* https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#max-java.util.Comparator-
*/
public static String longestPalindromeRegular(String wordListFileName) throws IOException {
String longest = "";
try (Scanner sc = new Scanner(new File(wordListFileName))) {
String line;
while (sc.hasNextLine()) {
line = sc.nextLine();
if (isPalindrome(line) && line.length() > longest.length()) {
longest = line;
}
}
}
return longest;
}
/** 3. Returns the longest palindrome in word list. */
public static String longestPalindromeStream(String wordListFileName) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get(wordListFileName))) {
return lines.filter(s->isPalindrome(s)).max((a, b) -> a.length() - b
.length())
.get();
}
}
/** 4. Returns the sum of all integers in the given collection
* satisfying the given criterion.
*
* HINT:
*
* You can get a stream from a collection using:
* https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream--
*
* You can also combine a stream's elements into a single value using:
* https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#reduce-T-java.util.function.BinaryOperator-
*/
public static int sumAllSatisfyingRegular(Collection<Integer> numbers, Predicate<Integer> criterion) {
int result = 0;
for (int num : numbers)
if (criterion.test(num))
result += num;
return result;
}
/** 4. Returns the sum of all integers in the given collection
* satisfying the given criterion.
*/
public static int sumAllSatisfyingStream(Collection<Integer> numbers, Predicate<Integer> criterion) {
return numbers.stream().filter(criterion).mapToInt(a->(int)a).sum();
}
/** 5. Returns a frequency table describing the given collection.
* HINTS:
*
* You can merge a stream into a map using this Collector, which is analogous to Map.merge:
* https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-
* Using this Collector requires three functions. While you could use lambdas for all three, the first
* can be found in java.util.function.Function, and the third can be found in java.lang.Integer.
*/
public static <E> Map<E, Integer> frequencyTableRegular(Collection<E> coll) {
Map<E, Integer> result = new HashMap<>();
for (E e : coll)
result.merge(e, 1, Integer::sum);
return result;
}
/** 5. Returns a frequency table describing the given collection. */
public static <E> Map<E, Integer> frequencyTableStream(Collection<E> coll) {
return
// 1. create stream
coll.stream()
// 2. process (nothing to do here).
// 3. compute final result
.collect(Collectors.toMap(
e -> e, // maps from E to the key of the map (E). alternative: Function.identity()
unused -> 1, // maps from E to the value of the map (Integer)
(x1, x2) -> x1 + x2 // merges values that the same key maps to. Alternative: Integer::sum
));
}
/** 6. Returns a list consisting of all the characters in all the given
* strings, in order.
*
* HINT:
* Use flatMap and friends to generate multiple elements from one element
* https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#flatMap-java.util.function.Function-
*/
public static List<Character> charactersInStringsRegular(String... strings) {
List<Character> result = new ArrayList<>();
for (String s : strings)
for (char c : s.toCharArray())
result.add(c);
return result;
}
/** 6. Returns a list consisting of all the characters in all the given
* strings, in order.
*/
public static List<Character> charactersInStringsStream(String... strings) {
return Arrays.stream(strings)
.flatMap(s->s.chars().mapToObj(a->Character.valueOf((char)a)))
.collect(Collectors.toList());
// return Arrays.stream(strings)
// // 2. Convert each string to a stream of characters.
// // flatMap then returns the concatenation of these character streams.
// .flatMap(s -> s.chars()
// .mapToObj(i -> Character.valueOf((char) i)))
// // 3. terminal operation
// .collect(Collectors.toList());
}
/** An example of infinite Streams. */
public static Stream<BigInteger> positives() {
BigInteger[] nextVal = { BigInteger.ONE };
return Stream.generate(() -> {
BigInteger result = nextVal[0];
nextVal[0] = result.add(BigInteger.ONE);
return result;
});
}
/** 7. Returns an infinite stream of the Fibonacci numbers. */
public static Stream<BigInteger> fibonacciNumbers() {
BigInteger[] fibs = { BigInteger.ZERO, BigInteger.ONE };
return Stream.generate(() ->{
BigInteger a = fibs[0];
BigInteger b = fibs[1];
fibs[0] = b;
fibs[1] = a.add(b);
return a;
});
}
/** 8. Returns the first Fibonacci number greater than or equal to
* the input parameter n.
*/
public static BigInteger firstFibStartingFrom(BigInteger n) {
return fibonacciNumbers().filter(s->s.compareTo(n) >= 0).findFirst()
.get();
}
/** 9. Returns the whether the input argument n is a Fibonacci number. */
public static boolean isFib(BigInteger n) {
return firstFibStartingFrom(n).equals(n);
}
/** 10. Returns the nth Fibonacci number, with 0 being the 0th
* Fibonacci number.
*/
public static BigInteger nthFib(int n) {
return fibonacciNumbers().skip(n).findFirst().get();
}
}