Does it exist better way to parse String to Integer using stream than this :
String line = "1 2 3 4 5";
List<Integer> elements = Arrays.stream(line.split(" ")).mapToInt(x -> Integer.parseInt(x))
.boxed().collect(Collectors.toList());
You can eliminate one step if you parse the String directly to Integer:
String line = "1 2 3 4 5";
List<Integer> elements = Arrays.stream(line.split(" ")).map(Integer::valueOf)
.collect(Collectors.toList());
Or you can stick to primitive types, which give better performance, by creating an int array instead of a List<Integer>:
int[] elements = Arrays.stream(line.split(" ")).mapToInt(Integer::parseInt).toArray ();
You can also replace
Arrays.stream(line.split(" "))
with
Pattern.compile(" ").splitAsStream(line)
I'm not sure which is more efficient, though.
There's one more way to do it that will be available since java-9 via Scanner#findAll:
int[] result = scan.findAll(Pattern.compile("\\d+"))
.map(MatchResult::group)
.mapToInt(Integer::parseInt)
.toArray();
Related
I'm attempting a block of code that I can't get quite right. I have a list with say, 1000 string entries (of 3 - 10 characters each) that I collect into a single comma-delimited string. If the total size of the characters in the resulting string is more than 8100, I need to split the list and create TWO comma-delimited strings (or 3, or whatever factor of 8100). I know this needs a groupingBy, but my syntax isn't working.
So my first question is, how can I determine the sum of the characters in my list, and how can I group the list such that there are no more than 8100 characters in each group of lists? This is what I have so far:
AtomicInteger counter = new AtomicInteger();
String codes = configInfos.stream()
.map(ConfigInfo::getCode)
.collect(Collectors.groupingBy(it -> counter.getAndIncrement() / 8100))
This needs to be solved with Streams?
Otherwise I would solve it like this:
String [] array = configInfos
.stream()
.map( ConfigInfo::getCode )
.toArray( String []::new );
List<String> codes = new ArrayList<>();
StringJoiner joiner = new StringJoiner( "," );
for( String s : array )
{
if( joiner.length() + 1 + s.length() > 8100 )
{
codes.add( joiner.toString() );
joiner = new StringJoiner( "," );
}
joiner.add( s );
}
if( joiner.length() > 0 ) codes.add( joiner.toString() );
But I have to confess, I have no clue how to solve this with Streams …
Edit: don’t use streams for this
I need the string maintained when I do the split. It has to look like
the original list, with list 1 being "Entries", "are". List 2 would be
"three", "upto". List 3 would be "ten", "chars", and so on.
Stream operations are not suited for your task. I recommend you use a classical loop for the clearest and easiest to maintain code.
Original answer: Intstream.range()
Not sure this is really what you want. In case you prefer to use a stream, here’s my attempt at that.
final int maxSubstringLength = 9; // 8100
List<String> entries = List.of("Entries", "are", "three", "upto", "ten", "chars", "each");
String totalString = entries.stream().collect(Collectors.joining(","));
// round up in the division
int substringCount = (totalString.length() + maxSubstringLength - 1) / maxSubstringLength;
List<String> substrings = IntStream.range(0, substringCount)
.mapToObj(i -> totalString.substring(i * maxSubstringLength, Math.min((i + 1) * maxSubstringLength, totalString.length())))
.collect(Collectors.toList());
substrings.forEach(System.out::println);
Output:
Entries,a
re,three,
upto,ten,
chars,eac
h
For your very long string just put 8100 as max substring length where I put 9 for the demonstration.
My Question is inspired by this Question, but is aimed at using Java Streams to arrive an a List<Integer>.
I have this code that kind of works. It seems to be returning an ArrayList, presumably ArrayList<Integer>. But the compiler refuses to let me declare the result as such.
String input = "1 2 3 4 5";
Stream stream = Arrays.stream( input.split( " " ) );
var x = stream.map( s -> Integer.valueOf( ( String ) s ) ).collect( Collectors.toList() );
This runs when using the new var feature of recent Java versions.
System.out.println( x.getClass() );
System.out.println( x );
class java.util.ArrayList
[1, 2, 3, 4, 5]
I have two questions:
Why is x reported as an ArrayList yet I cannot declare x to be an ArrayList (error: incompatible types), such as:ArrayList<Integer> x = stream.map( s -> Integer.valueOf( ( String ) s ) ).collect( Collectors.toList() );
Is there a better way to use streams to convert this string of digits to a List of Integer?
First, your Stream is raw. Using a raw type means that anything that uses a type parameter is erased to its upper bound, here Object. So map returns another raw Stream and collect returns an Object. Easy fix: Stream<String>.
Stream<String> stream = Arrays.stream( input.split( " " ) );
Second, Collectors.toList is specified to return List<T>, or List<String> here.
There are no guarantees on the type, mutability, serializability, or thread-safety of the List returned; if more control over the returned List is required, use toCollection(Supplier).
If you aren't satisfied with List and you absolutely need an ArrayList, supply one:
.collect(Collectors.toCollection(ArrayList::new));
Incidentally, you can replace the lambda expression
s -> Integer.valueOf( ( String ) s )
with the method reference
Integer::valueOf
After these changes, your code might look like this:
String input = "1 2 3 4 5";
Stream< String > stream = Arrays.stream( input.split( " " ) );
List< Integer > x = stream.map( Integer::valueOf ).collect( Collectors.toList() );
Or, if you insist on precisely ArrayList rather than List, make that:
String input = "1 2 3 4 5";
Stream< String > stream = Arrays.stream( input.split( " " ) );
ArrayList< Integer > x = stream.map( Integer::valueOf ).collect( Collectors.toCollection( ArrayList::new ) );
Once these changes are made, this seems like a reasonably good way of converting a string containing space-separated integers to an ArrayList<Integer>. A minor improvement would be to change the split regular expression argument to "\\s+", to represent one or more whitespace characters. In case "1 2" arrives, with multiple spaces between numbers, this will prevent empty strings that would match in between space characters.
You can create an ArrayList, but you shouldn't:
ArrayList<Integer> x =
stream.map(Integer::valueOf)
.collect(Collectors.toCollection(ArrayList::new));
Refactoring:
List<Integer> x =
Arrays.stream(input.split(" "))
.map(Integer::valueOf)
.collect(Collectors.toList());
Or, with the Pattern.splitAsStream:
List<Integer> x =
Pattern.compile(" ").splitAsStream("1 2 3 4 5")
.map(Integer::valueOf)
.collect(Collectors.toList());
List<Integer> list = Arrays.stream("1 2 3 4 5".split(" ")).map(s -> Integer.valueOf(s)).collect(Collectors.toList());
This compiles. According to the collectors source code: "There are no guarantees on the type, mutability,
* serializability, or thread-safety of the {#code List} returned;"
Why is x reported as an ArrayList yet I cannot declare x to be an ArrayList.
Because
collect(...) is returning a statically inferred type, based on the type of the result of Collectors.toList().
That is (in this case) Collector<String,?,List<String>> ... according to the Collectors javadoc.
The fact that the actual object is an ArrayList is an implementation detail that could conceivably change in future versions of Java.
Is there a better way to use streams to convert this string of digits to a List of Integer?
I will leave that to others to say. However, I think that a simpler / cleaner way to do this is to not use streams for this task.
String input = "1 2 3 4 5";
var x = new ArrayList<>(Arrays.asList(input.split(" ")));
The above code is simpler and most likely more efficient than the streams-based versions I have seen.
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
does anyone know a faster way to convert string to int array?
Java V7
The format given is "4 343 234 -24" and so on. Spaces between the numbers, amount of numbers is known beforhand just as is the range within the numbers are
long[] array = new long[length];
for (int i = 0; i < length - 1; i++) {
array[i] = Integer.parseInt(n.substring(0, n.indexOf(' ')));
n = n.substring(n.substring(0, n.indexOf(' ')).length() + 1);
}
array[length - 1] = Integer.parseInt(n);
Using String.split() is by far the most efficient when you want to split by a single character (a space, in your case).
If you are aiming for maximal efficiency when splitting by spaces, then this would be a good solution:
List<Integer> res = new ArrayList<>();
Arrays.asList(kraft.split(" ")).forEach(s->res.add(Integer.parseInt(s)));
Integer[] result = res.toArray(new Integer[0]);
And this works for any number of numbers.
Splitting the input with the pattern \\s+ would handle one or more white-space characters, not only spaces, appearing between the numbers.
Stream.of(input.split("\\s+")).mapToInt(Integer::parseInt).toArray();
The mapToInt method returns an IntStream which provides the toArray method. This method returns an array containing the elements of the IntStream.
if You are using Java8 or higher version then you can get your expected output by writing this single line of code.
String str= "4 343 234 -24";
int[] intArr=Stream.of(str.split(" ")).mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(intArr));
How to remove String from an array by checking length and comparing text in Java?
Suppose user search for "Hi Tonki with Monkey"
String[] pattern = userSearchString.toLowerCase().split("\\s");
1) We want to remove "With" from pattern and
2) also want to remove pattern with less then 3 size like "Hi".
So pattern should contain Tonki and Monkey only.
It will be fuitful if anyone can suggest method from Apache Commons or Guava.
Using Java 1.6
A Java 8 solution would be to Stream the array and filter only the elements that you want, and collect it back into an array:
Arrays.stream(pattern)
.filter(word -> !word.equals("with"))
.filter(word -> word.length() >= 3)
.toArray(String[]::new);
A pre-Java 8 solution would be to filter the array manually. However, we'll have to create a new array; but because we do not know the size of the new array in advance, we can use a List<String> and collect it to an array after adding its respective elements:
List<String> list = new ArrayList<>();
for (String word : pattern) {
if (word.length() < 3 || word.equals("with")) {
continue;
}
list.add(word);
}
list.toArray(new String[list.size()]);
There's no need to use external libraries if they aren't required!