Convert Comma Separated Values to List<Long> - java

Assume I have a set of numbers like 1,2,3,4,5,6,7 input as a single String. I would like to convert those numbers to a List of Long objects ie List<Long>.
Can anyone recommend the easiest method?

You mean something like this?
String numbers = "1,2,3,4,5,6,7";
List<Long> list = new ArrayList<Long>();
for (String s : numbers.split(","))
list.add(Long.parseLong(s));
System.out.println(list);
Since Java 8 you can rewrite it as
List<Long> list = Stream.of(numbers.split(","))
.map(Long::parseLong)
.collect(Collectors.toList());
Little shorter versions if you want to get List<String>
List<String> fixedSizeList = Arrays.asList(numbers.split(","));
List<String> resizableList = new ArrayList<>(fixedSizeList);
or one-liner
List<String> list = new ArrayList<>(Arrays.asList(numbers.split(",")));
Bonus info:
If your data may be in form like String data = "1, 2 , 3,4"; where comma is surrounded by some whitespaces, the split(",") will produce as result array like ["1", " 2 ", " 3", "4"].
As you see second and third element in that array contains those extra spaces: " 2 ", " 3" which would cause Long.parseLong to throw NumberFormatException (since space is not proper numerical value).
Solution here is either:
using String#trim on those individual elements before parsing like Long.parseLong(s.trim())
consuming those extra whitespace along , while splitting. To do that we can use split("\\s*,\\s*") where
\s (written as "\\s" in string literals) represents whitespace
* is quantifier representing zero or more
so "\\s*" represents zero or more whitespaces (in other words makes it optional)

Simple and handy solution using java-8 (for the sake of completion of the thread):
String str = "1,2,3,4,5,6,7";
List<Long> list = Arrays.stream(str.split(",")).map(Long::parseLong).collect(Collectors.toList());
System.out.println(list);
[1, 2, 3, 4, 5, 6, 7]
Even better, using Pattern.splitAsStream():
Pattern.compile(",").splitAsStream(str).map(Long::parseLong).collect(Collectors‌​.toList());

String input = "1,2,3,4,5,6,7";
String[] numbers = input.split("\\,");
List<Integer> result = new ArrayList<Integer>();
for(String number : numbers) {
try {
result.add(Integer.parseInt(number.trim()));
} catch(Exception e) {
// log about conversion error
}
}

You can use String.split() and Long.valueOf():
String numbers = "1,2,3,4,5,6,7";
List<Long> list = new ArrayList<Long>();
for (String s : numbers.split(","))
list.add(Long.valueOf(s));
System.out.println(list);

If you're not on java8 and don't want to use loops, then you can use Guava
List<Long> longValues = Lists.transform(Arrays.asList(numbersArray.split(",")), new Function<String, Long>() {
#Override
public Long apply(String input) {
return Long.parseLong(input.trim());
}
});
As others have mentioned for Java8 you can use Streams.
List<Long> numbers = Arrays.asList(numbersArray.split(","))
.stream()
.map(String::trim)
.map(Long::parseLong)
.collect(Collectors.toList());

I've used the following recently:
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
...
final ImmutableList<Long> result = Splitter.on(",")
.trimResults()
.omitEmptyStrings()
.splitToStream(value)
.map(Long::valueOf)
.collect(toImmutableList());
This uses Splitter from Guava (to handle empty strings and whitespaces) and does
not use the surprising String.split().

I would use the excellent google's Guava library to do it. String.split can cause many troubles.
String numbers="1,2,3,4,5,6,7";
Iterable<String> splitIterator = Splitter.on(',').split(numbers);
List<String> list= Lists.newArrayList(splitIterator );

Related

Extracting values corresponding to a certain "key" from a string List in Java [duplicate]

I have a String that's formatted like this:
"key1=value1;key2=value2;key3=value3"
for any number of key/value pairs.
I need to check that a certain key exists (let's say it's called "specialkey"). If it does, I want the value associated with it. If there are multiple "specialkey"s set, I only want the first one.
Right now, I'm looking for the index of "specialkey". I take a substring starting at that index, then look for the index of the first = character. Then I look for the index of the first ; character. The substring between those two indices gives me the value associated with "specialkey".
This is not an elegant solution, and it's really bothering me. What's an elegant way of finding the value that corresponds with "specialkey"?
I would parse the String into a map and then just check for the key:
String rawValues = "key1=value1;key2=value2;key3=value3";
Map<String,String> map = new HashMap<String,String>();
String[] entries = rawValues.split(";");
for (String entry : entries) {
String[] keyValue = entry.split("=");
map.put(keyValue[0],keyValue[1]);
}
if (map.containsKey("myKey")) {
return map.get("myKey");
}
Use String.split:
String[] kvPairs = "key1=value1;key2=value2;key3=value3".split(";");
This will give you an array kvPairs that contains these elements:
key1=value1
key2=value2
key3=value3
Iterate over these and split them, too:
for(String kvPair: kvPairs) {
String[] kv = kvPair.split("=");
String key = kv[0];
String value = kv[1];
// Now do with key whatever you want with key and value...
if(key.equals("specialkey")) {
// Do something with value if the key is "specialvalue"...
}
}
If it's just the one key you're after, you could use regex \bspecialkey=([^;]+)(;|$) and extract capturing group 1:
Pattern p = Pattern.compile("\\bspecialkey=([^;]+)(;|$)");
Matcher m = p.matcher("key1=value1;key2=value2;key3=value3");
if (m.find()) {
System.out.println(m.group(1));
}
If you're doing something with the other keys, then split on ; and then = within a loop - no need for regex.
Just in case anyone is interested in a pure Regex-based approach, the following snippet works.
Pattern pattern = Pattern.compile("([\\w]+)?=([\\w]+)?;?");
Matcher matcher = pattern.matcher("key1=value1;key2=value2;key3=value3");
while (matcher.find()) {
System.out.println("Key - " + matcher.group(1) + " Value - " + matcher.group(2);
}
Output will be
Key - key1 Value - value1
Key - key2 Value - value2
Key - key3 Value - value3
However, as others explained before, String.split() is recommended any day for this sort of task. You shouldn't complicate your life trying to use Regex when there's an alternative to use.
There are many ways to do this. Perhaps the simplest is to use the Streams API (available as of Java 8 and later) to process the match results:
List<String> OriginalList = Arrays.asList("A=1,B=2,C=3",
"A=11,B=12,C=13,D=15", "A=5,B=4,C=9,D=10,E=13",
"A=19,B=20,C=91,D=40,E=33", "A=77,B=27,C=37");
this streams the strings
matches on the pattern and extracts the integer
the collects to a list
Pattern p = Pattern.compile("A=(\\d+)");
List<Integer> result = OriginalList.stream().
flatMap(str->p.matcher(str).results())
.map(mr->Integer.valueOf(mr.group(1)))
.collect(Collectors.toList());
System.out.println(result);
Prints:
[1, 11, 5, 19, 77]
Try : (?:(?:A=)([^,]*))
Demo : https://regex101.com/r/rziGDz/1
Else you find a code using regex and your list to get answer :
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.*;
public class Main
{
public static void main(String[] args)
{
List<Integer> results = new ArrayList();
Pattern pattern = Pattern.compile("(?:(?:A=)([^,]*))", Pattern.CASE_INSENSITIVE);
List<String> OriginalList = Arrays.asList(
"A=1,B=2,C=3",
"A=11,B=12,C=13,D=15",
"A=5,B=4,C=9,D=10,E=13",
"A=19,B=20,C=91,D=40,E=33",
"A=77,B=27,C=37");
for (int i = 0; i < OriginalList.size(); i++)
{
Matcher matcher = pattern.matcher(OriginalList.get(i));
boolean matchFound = matcher.find();
if(matchFound)
{
System.out.println( matcher.group(1) );
results.add( Integer.parseInt(matcher.group(1)) );
}
}
}
}
This may be implemented using Stream API by simple splitting of each string in the input list by comma and Stream::flatMap
// assuming A is not always at the beginning
List<String> list = Arrays.asList(
"A=1,B=2,C=3",
"A=11,B=12,C=13,D=15",
"A=5,B=4,C=9,D=10,E=13",
"B=20,C=91,D=40,E=33",
"B=27, A=19, C=37, A=77");
List<Integer> aNums = list.stream() // Stream<String>
.flatMap(
s -> Arrays.stream(s.split("\\s*,\\s*")) // Stream<String> pairs of letter=digits
.filter(pair -> pair.startsWith("A="))
.map(pair -> Integer.valueOf(pair.substring(2)))
)
.collect(Collectors.toList());
System.out.println(aNums);
Output:
[1, 11, 5, 19, 77]
Update
A pattern to split an input string and keep only the digits related to A may be applied as follows:
Pattern splitByA = Pattern.compile("A\\s*=\\s*|\\s*,\\s*|[^A]\\s*=\\s*\\d+");
List<Integer> aNums2 = list.stream()
.flatMap(splitByA::splitAsStream) // Stream<String>
.filter(Predicate.not(String::isEmpty)) // need to remove empty strings
.map(Integer::valueOf)
.collect(Collectors.toList());
System.out.println(aNums2);
Output is the same
[1, 11, 5, 19, 77]
Using basic filter: Split using [A-Z=,]+ regex. Pick the 2nd element.
public List filter() {
List<String> originalList = Arrays.asList("A=1,B=2,C=3", "A=11,B=12,C=13,D=15", "A=5,B=4,C=9,D=10,E=13",
"A=19,B=20,C=91,D=40,E=33", "A=77,B=27,C=37");
List<Integer> parsedData = new ArrayList();
for(String str: originalList) {
Integer data = Integer.parseInt(str.split("[A-Z=,]+")[1]);
parsedData.add(data);
}
return parsedData;
}
Try this:
List<Integer> results = new ArrayList();
Pattern p = Pattern.compile("(?:(?:A=)([^,]*))");
Matcher m = null;
for (String tmp : OriginalList) {
m = p.matcher(tmp);
if (m.find()) {
int r = Integer.parseInt(m.group(0).replace("A=", ""));
results.add(r);
}
}

Using Java 8 streams with lambdas to process a for loop, invoking a method with multiple parms

I have a for loop, processing two string lists, which invokes a method with multiple parms, returning an object, which gets added to a List
I want to effectively utilize stream/lambda for this, can someone guide me
I have two incoming string lists "AAA, BBB, CCC" and a corresponding list of quantities as "1, 3, 11"
final List<someObj> someObjs = new ArrayList<someObj>() ;
final List<String> codesList = Arrays.asList(codes.split("\\s*,\\s*"));
final List<String> qtysList = Arrays.asList(qtys.split("\\s*,\\s*"));
for (String code: codesList){
someObjs.add(addThis(code, qtysList.get(index++)));//
}
return someObj;
How can I convert this using lambdas ? Thanks in advance !
How about this,
final List<SomeObj> someObjs = IntStream.range(0, codesList.size())
.mapToObj(i -> addThis(codesList.get(i), qtysList.get(i)))
.collect(Collectors.toList());

Parsing String by pattern of substrings

I need to parse a formula and get all the variables that were used. The list of variables is available. For example, the formula looks like this:
String f = "(Min(trees, round(Apples1+Pears1,1)==1&&universe==big)*number";
I know that possible variables are:
String[] vars = {"trees","rivers","Apples1","Pears1","Apricots2","universe","galaxy","big","number"};
I need to get the following array:
String[] varsInF = {"trees", "Apples1","Pears1", "universe", "big","number"};
I believe that split method is good here but can’t figure the regexp required for this.
No need for any regex pattern - just check which item of the supported vars is contained in the given string:
List<String> varsInf = new ArrayList<>();
for(String var : vars)
if(f.contains(var))
varsInf.add(var);
Using Stream<> you can:
String[] varsInf = Arrays.stream(vars).filter(f::contains).toArray(String[]::new);
Assuming "variable" is represented by one alphanumeric character or sequential sequence of multiple such characters, you should split by not-alphanumeric characters, i. e. [^\w]+, then collect result by iteration or filter:
Set<String> varSet = new HashSet<>(Arrays.asList(vars));
List<String> result = new ArrayList<>();
for (String s : f.split("[^\\w]+")) {
if (varSet.contains(s)) {
result.add(s);
}
}

Java Streams: Is there a cleaner way of doing this?

I am using streams to concatenate a series of strings and add commas between them, but there must be no comma at the beginning or the end of the result string.
import java.util.Arrays;
import java.util.List;
public class QuestionNine {
public static void main(String[] args) {
new QuestionNine().launch();
}
public void launch(){
List<String> words = Arrays.asList("Hello", "Bonjour", "engine", "Hurray", "What",
"Dog", "boat", "Egg", "Queen", "Soq", "Eet");
String result = (words.stream().map(str -> str + ",").reduce("", (a,b) -> a + b));
result = result.substring(0, result.length() -1); //removes last comma
System.out.println(result);
}
}
Instead of using the String.substring() method at the end to get rid of the last comma, is there a way i could have deleted the last comma within the stream pipeline?
The usual idiom is to use the joining Collector with Streams.
String res = words.stream().collect(Collectors.joining(","));
Although you can use String.join in your case since you are directly dealing with an Iterable.
String res = String.join(",", words);
The problem with your approach is that the mapping function you apply impose that there will be a comma at the end of each word. You could get rid of this mapping; and apply the reduce function such that you get the desired output:
.stream().reduce("", (a,b) -> a.isEmpty() ? b : a+","+b);
but I don't recommend this.
Yes, you can use Collectors.joining() here:
String joined = words.stream().collect(Collectors.joining(", "));
Or, also as noted from comments, you can use newly added String.join(CharSequence, Iterable) method.
String joined = String.join(", ", words);

Fastest way to put contents of Set<String> to a single String with words separated by a whitespace?

I have a few Set<String>s and want to transform each of these into a single String where each element of the original Set is separated by a whitespace " ".
A naive first approach is doing it like this
Set<String> set_1;
Set<String> set_2;
StringBuilder builder = new StringBuilder();
for (String str : set_1) {
builder.append(str).append(" ");
}
this.string_1 = builder.toString();
builder = new StringBuilder();
for (String str : set_2) {
builder.append(str).append(" ");
}
this.string_2 = builder.toString();
Can anyone think of a faster, prettier or more efficient way to do this?
With commons/lang you can do this using StringUtils.join:
String str_1 = StringUtils.join(set_1, " ");
You can't really beat that for brevity.
Update:
Re-reading this answer, I would prefer the other answer regarding Guava's Joiner now. In fact, these days I don't go near apache commons.
Another Update:
Java 8 introduced the method String.join()
String joined = String.join(",", set);
While this isn't as flexible as the Guava version, it's handy when you don't have the Guava library on your classpath.
If you are using Java 8, you can use the native
String.join(CharSequence delimiter, Iterable<? extends CharSequence> elements)
method:
Returns a new String composed of copies of the CharSequence elements joined together with a copy of the specified delimiter.
For example:
Set<String> strings = new LinkedHashSet<>();
strings.add("Java"); strings.add("is");
strings.add("very"); strings.add("cool");
String message = String.join("-", strings);
//message returned is: "Java-is-very-cool"
Set implements Iterable, so simply use:
String.join(" ", set_1);
As a counterpoint to Seanizer's commons-lang answer, if you're using Google's Guava Libraries (which I'd consider the 'successor' to commons-lang, in many ways), you'd use Joiner:
Joiner.on(" ").join(set_1);
with the advantage of a few helper methods to do things like:
Joiner.on(" ").skipNulls().join(set_1);
// If 2nd item was null, would produce "1, 3"
or
Joiner.on(" ").useForNull("<unknown>").join(set_1);
// If 2nd item was null, would produce "1, <unknown>, 3"
It also has support for appending direct to StringBuilders and Writers, and other such niceties.
Maybe a shorter solution:
public String test78 (Set<String> set) {
return set
.stream()
.collect(Collectors.joining(" "));
}
or
public String test77 (Set<String> set) {
return set
.stream()
.reduce("", (a,b)->(a + " " + b));
}
but native, definitely faster
public String test76 (Set<String> set) {
return String.join(" ", set);
}
I don't have the StringUtil library available (I have no choice over that) so using standard Java I came up with this ..
If you're confident that your set data won't include any commas or square brackets, you could use:
mySet.toString().replaceAll("\\[|\\]","").replaceAll(","," ");
A set of "a", "b", "c" converts via .toString() to string "[a,b,c]".
Then replace the extra punctuation as necesary.
Filth.
I use this method:
public static String join(Set<String> set, String sep) {
String result = null;
if(set != null) {
StringBuilder sb = new StringBuilder();
Iterator<String> it = set.iterator();
if(it.hasNext()) {
sb.append(it.next());
}
while(it.hasNext()) {
sb.append(sep).append(it.next());
}
result = sb.toString();
}
return result;
}
I'm confused about the code replication, why not factor it into a function that takes one set and returns one string?
Other than that, I'm not sure that there is much that you can do, except maybe giving the stringbuilder a hint about the expected capacity (if you can calculate it based on set size and reasonable expectation of string length).
There are library functions for this as well, but I doubt they're significantly more efficient.
This can be done by creating a stream out of the set and then combine the elements using a reduce operation as shown below (for more details about Java 8 streams check here):
Optional<String> joinedString = set1.stream().reduce(new
BinaryOperator<String>() {
#Override
public String apply(String t, String u) {
return t + " " + u;
}
});
return joinedString.orElse("");

Categories

Resources