This question already has answers here:
Simple way to repeat a string
(32 answers)
Closed 4 years ago.
There are numerous ways to do this, but using Java 8 streams (likely IntStream), how can I produce a dummy string that is N characters long?
I've seen examples using IntStream.range(), and the various aggregator functions (sum, average), but I don't see a way to do this.
My first random guess looks like this:
IntStream.range(1, 110).map(i -> "x").collect(Collectors.joining());
But that's wrong in a couple of different ways.
You need to use mapToObj() and not map() as you actually use an IntStream and IntStream.map() takes as parameter an IntUnaryOperator, that is an (int->int) function.
For same character dummy (for example "x") :
collect = IntStream.range(1, 110)
.mapToObj(i ->"x")
.collect(Collectors.joining());
Form random dummy :
You could use Random.ints(long streamSize, int randomNumberOrigin, int randomNumberBound).
Returns a stream producing the given streamSize number of pseudorandom
int values, each conforming to the given origin (inclusive) and bound
(exclusive).
To generate a String containing 10 random characters between the 65 and 100 ASCII code :
public static void main(String[] args) {
String collect = new Random().ints(10, 65, 101)
.mapToObj(i -> String.valueOf((char) i))
.collect(Collectors.joining());
System.out.println(collect);
}
If you really want to use a Stream for this, you can utilize Stream#generate, and limit it to n characters:
Stream.generate(() -> "x").limit(110).collect(Collectors.joining());
You are actually almost there:
String s = IntStream.range(40, 110)
.mapToObj(i -> Character.toString((char)i))
.collect(Collectors.joining());
System.out.println(s);
Produces:
()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklm
If you want random ordering, with N = 60 for instance:
Random r = new Random();
IntStream.generate(() -> 40 + r.nextInt(70))
.limit(60)
.mapToObj(i -> Character.toString((char)i))
.collect(Collectors.joining()));
Produces
Z>fA+5OY#:HfP;(L:^WKDU21T(*1//#V,F9O-SA2;+),A+V/mLjm<eaE56CH
Related
I have to calculate the digit sum of a string (read in via Scanner) in a one liner. Also, I have to make sure that the input is only calculated if the input has exactly 3 digits.
What I got so far:
public class Test{
public static void main(String... args) {
System.out.print(new java.util.Scanner(System.in).nextLine().chars().mapToObj(i -> ((char)i)-'0').reduce(0, (a,b)->a+b));
}
}
But how can I proof in that one liner that there are exactly 3 digits?
Wrap your code in an Optional that uses filter() to check the length and orElse() to provide the output for bad length input:
System.out.print(Optional.of(new Scanner(System.in).nextLine())
.filter(str -> str.matches("\\d{3}")).map(str -> str.chars().sum() - '0' * 3)
.orElse("invalid input"));
Note that you can replace:
.mapToObj(i -> ((char)i)-'0').reduce(0, (a,b)->a+b)
with:
.map(i -> ((char)i)-'0').sum()
or, because you have exactly 3 digits, just:
.sum() - '0' * 3
So this could be something like this. Line breaks added for readabiliy
public static void main(String... args) {
System.out.print(
//Make input into String-Stream
Arrays.asList(new java.util.Scanner(System.in).nextLine()).stream()
//Throw away averything not three digits
.filter(s -> s.matches("\\d{3}"))
//Perform digit-sum (make it a String)
.map(e -> ""+e.chars().mapToObj(i -> ((char)i)-'0').reduce(0, (a,b)->a+b))
//return this if there is something
.findFirst()
//Or give error message
.orElse("No valid input!"));
}
How about this. The lack of output indicates bad input (since you didn't specify what to do in that case).
Stream.of(new Scanner(System.in).nextLine()).
// three digits
filter(s->s.matches("\\d{3}"))
// convert to integer
.map(Integer::valueOf)
// find the sum
.map(n->n/100 + (n/10)%10 + n%10)
// and print it
.forEach(System.out::println);
If you want an error message, you could do the following:
System.out.println(Stream.of(new Scanner(System.in)
.nextLine())
.filter(a -> a.matches("\\d{3}"))
.map(Integer::valueOf)
.map(a -> a / 100 + (a / 10) % 10 + a % 10)
// convert back to string
.map(Object::toString)
.findFirst()
.orElse("Not 3 digits"));
I am new to Java stream, I was trying to split integer like (12345) to individual value 1, 2, 3 ... and I did it like as bellow.
int number = 123456;
(number+"").chars()
.mapToObj(e -> (char) e)
.map(e -> Integer.parseInt(""+e))
.forEach(System.out::println);
It works for me though but I am not sure, is it the correct way of doing it?
Without multiple cast and mappings :
Stream.of(String.valueOf(number).split("")).forEach(System.out::println);
I need to find 1st free index in my file system having stream of names as source.
Consider list: ["New2", "New4", "New0", "New1", ...]
1st unused index of those will be 3.
int index = 0;
try (IntStream indexes = names.stream()
.filter(name -> name.startsWith("New"))
.mapToInt(Integer::parseInt)
.distinct()
.sorted())
{
// I was thinking about making possible indexes stream, removing existig ones from try-with-resource block, and getting .min().
IntStream.rangeClosed(0, 10)... // Idk what to do.
}
I am asking someone to help me find right syntax for my idea or propose better solution.
The most efficient way is to collect into a BitSet:
int first = names.stream()
.filter(name -> name.startsWith("New"))
.mapToInt(s -> Integer.parseInt(s.substring(3)))
.collect(BitSet::new, BitSet::set, BitSet::or).nextClearBit(0);
Note that the bits are intrinsically sorted and distinct. Also, there will always be a “free” index. If there is no gap between 0 and the maximum number, the next free will be maximum+1, if there are no matching elements at all, the next free will be zero.
Starting with Java 9, we can do even more efficient with
int first = names.stream()
.filter(name -> name.startsWith("New"))
.mapToInt(s -> Integer.parseInt(s, 3, s.length(), 10))
.collect(BitSet::new, BitSet::set, BitSet::or).nextClearBit(0);
which parses the relevant part of the string directly, saving the substring operation.
You could:
Extract the numeric part from each name
Store the used indexes in a set
Iterate over the range from 0 until the size of the list
The first index not in the used set is available
For example like this:
List<String> names = Arrays.asList("New2", "New4", "New0", "New1");
Set<Integer> taken = names.stream()
.map(s -> s.replaceAll("\\D+", ""))
.map(Integer::parseInt)
.collect(Collectors.toSet());
int first = IntStream.range(0, names.size())
.filter(index -> !taken.contains(index))
.findFirst()
.orElse(names.size());
For the fun of it, if you know you have up to 63 entries...
private static int firstMissing(List<Long> input) {
if (!input.contains(0L)) {
return 0;
}
long firstMissing = Long.lowestOneBit(~input.stream().reduce(1L, (i, j) -> i | 1L << j));
int result = 0;
while (firstMissing != 0) {
++result;
firstMissing = firstMissing >> 1;
}
return result - 1;
}
That's what #Holger did (+1 from me), but without the extra penalty of using BitSet.
This question already has answers here:
Is there a concise way to iterate over a stream with indices in Java 8?
(24 answers)
Closed 6 years ago.
How can I add the counter value to every nth item while iterating though a Stream?
Here is my simplest code:
Stream.of("a1","a2","a3")
.map(x -> x + "counterValue")
.findFirst()
.ifPresent(System.out::println);
As I am adding "counterValue" string with every nth item, what I want to achieve is to add the ith value with every nth element.
The current program gives the output as a1counterValue.
I want the output as a10. 0 mean the index of that element.
Can anybody please help?
Is this what you are looking for?
List<String> input = Arrays.asList("one", "two");
IntStream.range(0, input.size())
.mapToObj(i -> input.get(i) + i)
.collect(Collectors.toList()) // [one0, two1]
You can iterate using index by using IntStream as shown below:
String[] arr = {"a1","a2","a3"};
int lentgh = arr.length;
IntStream.of(0, lentgh).
mapToObj(((int i) -> i + arr[i])).findFirst().
ifPresent(System.out::println);
I'm working on an assignment for a Computer Science III class (Java programming), and in it we have to encode a file based on Huffman coding.
import java.util.Scanner;
import java.util.ArrayList;
import java.io.*;
import java.util.Collections;
import java.util.StringTokenizer;
public class Client {
public static void main(String[] args) throws IOException {
// TODO code application logic here
Scanner in = new Scanner(System.in);
System.out.println("Enter a filename to read from.");
String filename = in.nextLine();
File file = new File(filename);
Scanner inputFile = new Scanner(file);
String line, word;
StringTokenizer token;
ArrayList<Character> chars = new ArrayList<>();
while(inputFile.hasNext()){
line = inputFile.nextLine();
ArrayList<Character> lineChar = new ArrayList<>();
for (int i=0; i<line.length(); i++){
if (line.charAt(i)!=' '){
lineChar.add(line.charAt(i));
}
}
chars.addAll(lineChar);
}
ArrayList<Character> prob = new ArrayList<Character>();
for (int i=0; i<chars.size(); i++){
if (!prob.contains(chars.get(i))){
prob.add(chars.get(i));
}
}
for (int i=0; i<prob.size(); i++){
System.out.print("Frequency of " + prob.get(i));
System.out.println(": " + ((double)Collections.frequency(chars, prob.get(i)))/chars.size());
}
I was working on it in my NetBeans IDE and followed some suggestions. It changed the last two for loops to:
chars.stream().filter((char1) -> (!prob.contains(char1))).forEach((char1) -> {
prob.add(char1);
});
prob.stream().map((prob1) -> {
System.out.print("Frequency of " + prob1);
return prob1;
}).forEach((prob1) -> {
System.out.println(": " + ((double) Collections.frequency(chars, prob1)) / chars.size());
});
I am really, really, really intrigued by this, but I find it difficult to trace everything. It obviously operates in the same way as my for loops and after testing I see that it -does- work, but I want to understand why and how. Can anybody give me any insight?
Your IDE replaced some of your code with new Java 8 features - Streams and lambda expressions. You should read about them.
Streams allow you to perform operations on a collection in a pipeline, where only the final (terminal) operation does the actual iteration over the elements (for only as many elements as it requires).
Lambda expressions allow you to write less code when passing anonymous class instances implementing functional interfaces (=interfaces with a single method) to methods.
Here's an attempt to explain what the new code does :
chars.stream() // creates a Stream<Character> from your chars List
.filter((char1) -> (!prob.contains(char1))) // keeps only Characters not contained
// in prob List
.forEach((char1) -> {prob.add(char1);}); // iterates over all the elements of
// the Stream (i.e. those that weren't
// filtered out) and adds them to prob
prob.stream() // creates a Stream<Character> of the prob List
.map((prob1) -> {
System.out.print("Frequency of " + prob1);
return prob1;
}) // prints "Frequency of " + character for the current Character in the Stream
.forEach((prob1) -> { // prints the frequency of each character in the Stream
System.out.println(": " + ((double) Collections.frequency(chars, prob1)) / chars.size());
});
The map operation on the second Stream is a bit strange. Usually map is used to convert a Stream of one type to a Stream of another type. Here it is used to print output and it returns the same Stream. I wouldn't use map for that. You can simply move the printing to the forEach.
prob.stream() // creates a Stream<Character> of the prob List
.forEach((prob1) -> { // prints the frequency of each character in the Stream
System.out.print("Frequency of " + prob1);
System.out.println(": " + ((double) Collections.frequency(chars, prob1)) / chars.size());
});
Actually, you don't need a Stream for that, since Collections also have a forEach method in Java 8 :
prob.forEach((prob1) -> { // prints the frequency of each character in the Stream
System.out.print("Frequency of " + prob1);
System.out.println(": " + ((double) Collections.frequency(chars, prob1)) / chars.size());
});
Netbeans did what it could to refactor your code to use java 8 streams, but it can actually be done much better. For example, it appears that prob is supposed to contain a distinct list of Characters. In java 8, you can do it like this:
List<Character> prob = chars.stream()
.distinct()
.collect(Collectors.toList());
But all you are using prob for is to then calculate how many times each Character appears in chars. With streams, you can do it without first making a prob list:
Map<Character, Long> freq = chars.stream()
.collect(
Collectors.groupingBy(
x->x,
Collectors.counting()
)
);
The static methods in Collections class are usually just imported statically, so the above would be written as:
Map<Character, Long> freq = chars.stream()
.collect(groupingBy(x->x, counting());
That means, take my stream of chars and make a map. The key of the map is the char itself (that's what x->x does) and the value of the map is the count of how many times that char occurs in chars.
But that's not all! The first half of your method goes over the lines of the file and collects the chars. That can be rewritten with streams as well:
Stream<Character> charStream = Files.lines(Paths.get(filename))
.flatMap(line -> line.chars().mapToObj(i->(char) i));
File.lines(..) gives us a stream of lines. The flatMap part is a bit cryptic, but it unrolls every string into a stream of individual chars and joins the streams so that we have one big stream of chars.
And now we put it all together:
public static void main(String[] args) throws IOException {
Scanner in = new Scanner(System.in);
System.out.println("Enter a filename to read from.");
String filename = in.nextLine();
Map<Character, Long> freq = Files.lines(Paths.get(filename))
.flatMap(line -> line.chars().mapToObj(i -> (char) i))
.collect(groupingBy(x -> x, counting()));
long total = freq.values().stream().mapToLong(x->x).sum();
freq.forEach((chr, count) ->
System.out.format("Frequency of %s: %s%n", chr, ((double) count) / total)
);
}
Edit:
To output frequencies in sorted order, do this (using import static java.util.Comparator.*):
freq.entrySet().stream()
.sorted(comparing(e->e.getValue(), reverseOrder()))
.forEach(e -> System.out.format("Frequency of %s: %s%n", e.getKey(), (double) e.getValue() / total));
We take the map of Character to count, stream its entries, sort them by values in reverse order and print each one out.
This to me looks like NetBeans refactored your code to use Java 8's lambda or functional programming operations using the map - reduce from the Stream interface.
For more information on map() / reduce()/ stream interface refer to this link
Please read the suggestions that the IDE provides before you apply them :)
First, you should read about the java.util.Stream package, to get a first impression of how the API is designed and for what purpoeses.
Here is what your first loop does, in word form:
Iterate over the values from 0 to chars.size()-1 and add the corresponding element from chars to prob, but only if it's not already there.
With the Stream API added to Java with Java 8 such tasks can be written in a functional programming style which focuses on the "how is it done" not on the "with what is ist done".
chars.stream()
.filter(char1 -> !prob.contains(char1))
.forEach(char1 -> {
prob.add(char1);
});
ArrayList implements Collection<T> and therefore the method stream().
This stream (all elements from the Collection in a pipeline) is being filtered (by your former if-statement)
On the stream of the remaining elements, execute the final operation prop.add
This might be a bit too much for now, but you can change the last operation (.forEach) to be even clearer:
//...
.forEach(prop::add);
For better insight or debuggin purposes you might find Stream#peek interesting which let.