Split Java List items within String - java

The code example below shows a Test class that is supposed to print the list out as follows:
'A','B','C' (note the quotation marks).
Is there a method I can use to do that kind of formatting directly within the String assignment?
public class TEST {
public static void main(String[] args) {
List<String> test = new ArrayList<>();
test.add("A");
test.add("B");
test.add("C");
System.out.println(test);
System.out.println("Expected: 'A','B','C'"); // wanted output
}
}
Output:
[A, B, C]
Expected: 'A','B','C'

One option to print the desired result would be to use String.join in System.out.format:
public static void main(String[] args) {
List<String> test = new ArrayList<>();
test.add("A");
test.add("B");
test.add("C");
System.out.format("'%s'", String.join("','", test));
}
This code produces the following output:
'A','B','C'
Applying this format directly within the String assignment can be done in a similar way, by combining String.format and String.join:
String formatted = String.format("'%s'", String.join("','", test));

You can use any of a variety of methods to do the conversion. You can then use your favorite method in a lambda like so. Here I am using deHaar's solution.
Function<List<String>, String> format = lst-> String.format("'%s'",
String.join("','", lst));
String result = format.apply(myList);
A somewhat more extreme solution is to create a method that returns an ArrayList with the toString method overridden. Unless you create a lot of lists of varying types and don't want to have to reformat the list, it is probably overkill. But it demonstrates a technique.
List<String> listString = createList(List.of("A","B","C"));
List<Integer> listInt = createList(List.of(1,2,3,4));
System.out.println(listString);
System.out.println(listInt);
prints
'A','B','C'
'1','2','3','4'
A single no arg method could be used and then the list populated. I added a helper to permit passing a Collection to populate the list upon creation.
the no arg method calls the the other with an empty list.
the single arg method simply returns an instance of the ArrayList with populated with the supplied collection and overriding the toString() method.
#SuppressWarnings("unchecked")
public static <T> List<T> createList() {
return createList(Collections.EMPTY_LIST);
}
public static <T> List<T> createList(Collection<T> list) {
return new ArrayList<T>(list) {
#Override
public String toString() {
return stream().map(s -> s + "")
.collect(Collectors.joining("','", "'", "'"));
}
};
}

Related

How peek and map works in streams

I am trying to understand how different peek and map in java 8 streams.I have tried the following
public static void main(String[] args) {
List<String> arr = new ArrayList<String>();
arr.add("A");
arr.add("B");
List<String> a = arr.stream().peek(t->t.toLowerCase()).collect(Collectors.toList());
System.out.println(a);
}
The above code is not changing the alphabets to lower case.But when i try the following
public static void main(String[] args) {
List<String> arr = new ArrayList<String>();
arr.add("A");
arr.add("B");
List<String> a = arr.stream().map(t->t.toLowerCase()).collect(Collectors.toList());
System.out.println(a);
}
The alphabets are converted to smaller case.My doubt here is if i use both map and peek like below
public static void main(String[] args) {
List<String> arr = new ArrayList<String>();
arr.add("A");
arr.add("B");
List<String> a = arr.stream().map(t->t.toLowerCase()).peek(t->toUpper()).collect(Collectors.toList());
System.out.println(a);
}
public static Function<String, String> toUpper(){
return t->{
return t.toUpperCase();
};
}
The map method converts A,B to lower and Peek does nothing.So if there is any calculation involved while streaming cant i make use of peek?Can someone explain
MOdified code
static List<Employee> e = new ArrayList<>();
public static void main(String[] args) {
List<String> arr = new ArrayList<String>();
arr.add("Pavan");
arr.add("Kumar");
System.out.println("Size of emp"+e.size());
List<String> a = arr.stream().map(t->t.toLowerCase()).peek(t->populateEmp()).collect(Collectors.toList());
System.out.println("Size of emp"+e.size());
System.out.println(a);
}
public static Function<String, Employee> populateEmp(){
Employee ee = new Employee();
return t->{
System.out.println(t);
ee.setName(t);
e.add(ee);
return ee;
};
}
This is still not adding the Emp to list
Peek expects a Consumer, so if you are using toLowerCase() you are creating a new String, which is put into void. You may modify this object inside of a consumer, but String is immutable, so peek has no effect.
When you use map, then you expect to pass a Function or UnaryOperator, that receives single object and returns single object. So new String that is lower-cased is returned.
In both cases, objects are not cloned. So you could modify an object that is mutable inside of a peek function, but that is just the wrong way to do it:) Try passing a Date, then you can set hours inside a peek function because it's mutable.
In short:
use map to transform model to another model
use peek, to do something that consumes this object, but does not modify it (send a notification, print model, etc)
UPDATE:
public static Function<String, Employee> populateEmp(){
Employee ee = new Employee();
System.out.print("I am executed");
return t->{
System.out.print("I am not");
return null;
};
}
Try with this code. In your update, you are passing a consumer, that ignores passed argument, and you execute populateEmp() method, which returns a function, that adds to a map transformed object. But you NEVER execute this function, tus-> list is empty:)
In non-lambda word it looks like this:
for(String value: arr){
populateEmp(); // execute method but you do nothing with this Function.
}
So replace your peek with this:
.peek(t->populateEmp().apply(t))

How to skip a particular string during string Joining in Java?

The source code I have uploaded it will join some strings value in a one line. I want a way that I can able to skip a particular string in time of string joining. Here i have stored the strings "This","is","a","test." in a string array. I want that in time of joining a particular string will be skipped. Like I want to skip "a". How can I able to do in Java? I want a generalized way that I will able to apply for any strings.
import java.util.StringJoiner;
public class Test_Joiner_for_seatPlan
{
public static void main(String[] args)
{
StringJoiner joinString = new StringJoiner( " ");
String[] testStringArray = {"This","is","a","test."};
String joinedString = null;
for(String s : testStringArray)
{
joinString.add(s);
}
joinedString = joinString.toString();
System.out.println("After Joining the String:\n"+joinedString);
}
}
Try with not equal condition with string. but its not feasible as its check everytime a value.
for(String s : testStringArray)
{
if(!s.equals("a")){
joinString.add(s);
}
}
If you have a list of values like a,b,c than you can do like this:
Set<String> exclude = new HashSet<String>(Arrays.asList("a","b","c"));
for(String s : testStringArray)
{
if(!exclude.contains(s)){
joinString.add(s);
}
}
Use Split method of string. It returns array. combine each of them to get the string.
for (String retval: Str.split("a")){
System.out.println(retval);
}
You can do it like this:
Code:
for(String s : testStringArray){
if(!s.equals("a")){ // replace 'a' with the required character or word you want to ignore
joinString.add(s);
}
}
One possible solution is to provide a Map or a List in which you store the String values that should get excluded in your join. Here is an example using a Map.
public static void main(String[] args) {
String[] testStringArray = {"This","is","a","test."};
Map<String, String> excludedStrings = createExcludingMap("a");
System.out.println("After Joining the String:\n" + join(testStringArray, excludedStrings));
}
private static String join(String[] inputData, Map<String, String> excludedStrings){
StringJoiner joinString = new StringJoiner( " ");
String joinedString = null;
for(String s : inputData)
{
if(excludedStrings.get(s) == null) // IF this return null, the String is not part of the Strings to be excluded, hence join the string
joinString.add(s);
}
joinedString = joinString.toString();
return joinString.toString();
}
private static Map<String, String> createExcludingMap(String... values) {
Map<String, String> output = new HashMap<>();
for(String s : values) { // Add each value to the map, with s as key
output.put(s, s);
}
return output;
}
output :/
After Joining the String:
This is test.
The StringJoiner is a utility class that was written specifically to be used with the new Java8 Stream functionality. The documentation of StringJoiner also refers to the Collectors.joining method. It creates the StringJoiner, and wraps it in an object suitable to pass to Stream.collect, actually a Collector.
As part of the Stream API we now also have direct support for filters, it is just a matter of employing the fluent API (fluent because we keep adding .something(...)) to add the .filter method.
You can use it as you did in your answer, but I would suggest doing it as follows:
import static java.util.stream.Collectors.joining;
import java.util.function.Predicate;
import java.util.stream.Stream;
public class App {
public static String joinString(String [] sa,Predicate<String> filter) {
return Stream.of(sa).filter(filter).collect(joining(" "));
}
public static void main(String[] args) {
String[] testStringArray = new String [] {"This","is","a","test."};
System.out.println(joinString(testStringArray,(s)->!s.equals("a")));
}
}
I have deliberately broken it up by defining an extra method, so you can see the type of the filter passed along, exposing the Predicate. This would also make your function a little more generic making it work as you stated: 'I want a generalized way that I will able to apply for any strings'.
However if the Stream api is flexible enough that I do not see any need to abstract your own API for it. I suggest using it as-is:
import static java.util.stream.Collectors.joining;
import java.util.stream.Stream;
public class App {
public static void main(String[] args) {
System.out.println(
Stream
.of(new String [] {"This","is","a","test."})
.filter((s)->!s.equals("a"))
.collect(joining(" "))
);
}
}
I could have written most of it on a single line, but I like to break it up for readability.

Collect values from list of POJO using Functional interfaces (lambdas)

How can I iterate over list of POJO classes for collecting result of some methods in a standard way to avoid copy past?
I want to have code like this:
//class 'Person' has methods: getNames(), getEmails()
List<Person> people = requester.getPeople(u.getId());
String names = merge(people, Person::getNames);
String emails = merge(people, Person::getEmails);
instead of such copy-pasted logic:
List<Person> people = requester.getPeople(u.getId());
Set<String> namesAll = new HashSet<>();
Set<String> emailsAll = new HashSet<>();
for (Person p : people) {
if(p.getNames()!=null) {
phonesAll.addAll(p.getNames());
}
if(p.getEmails()!=null) {
emailsAll.addAll(p.getEmails());
}
}
String names = Joiner.on(", ").skipNulls().join(namesAll);
String emails = Joiner.on(", ").skipNulls().join(emailsAll);
Thus, is it possible to implement some standard approach for iterating and processing special method of POJO in list that could be reused?
If I understand you correctly, you want something like this :
String names = people.stream().flatMap(p->p.getNames().stream()).distinct().collect(Collectors.joining(", "));
Now, if you want to save typing that line for each property, you can have this merge method as you suggested :
public static String merge (List<Person> people, Function<Person, Collection<String>> mapper)
{
return people.stream().flatMap(p->mapper.apply(p).stream()).distinct().collect(Collectors.joining(", "));
}
This would make your first snippet work.
Now, you can make this method generic :
public static <T> String merge (List<T> list, Function<T, Collection<String>> mapper)
{
return list.stream().flatMap(p->mapper.apply(p).stream()).distinct().collect(Collectors.joining(", "));
}
I think this should work (haven't tested it).

Is there a utility method to separate a list by given string?

Is there something like the following in Apache Common Lang or Spring Utils or do you write your own Util method for this?
List<String> list = new ArrayList<String>();
list.add("moo");
list.add("foo");
list.add("bar");
String enumeratedList = Util.enumerate(list, ", ");
assert enumeratedList == "moo, foo, bar";
I remember the use of implode in php, this is what i search for java.
$array = array('lastname', 'email', 'phone');
$comma_separated = implode(",", $array);
You can use StringUtils.join(Object[] array, String delimiter) (from commons-lang) in the following way:
String enumeratedList = StringUtils.join(list.toArray(), ", ");
Google Collections provides the Joiner class, which can be used like this:
public class Main {
public static void main(String[] args) {
List<String> list = Lists.newLinkedList();
list.add("1");
list.add("2");
list.add("3");
System.out.println(Joiner.on(", ").join(list));
}
}
It's pretty trivial to inplement if you don't want a dependency on commons-lang. It's also not great to convert a List to an Array simply to join it again into a String. Instead just iterate over your collection. Even better than using Collection is using Iterable which handles anything which can be iterator over (even some sort of stream or Collection of unknown length).
import java.util.Arrays;
import java.util.Iterator;
public class JoinDemo {
public static String join(String sep, Iterable<String> i) {
StringBuilder sb = new StringBuilder();
for (Iterator<String> it = i.iterator(); it.hasNext();) {
sb.append(it.next());
if (it.hasNext())
sb.append(sep);
}
return sb.toString();
}
public static void main(String[] args) {
System.out.println(join(",", Arrays.asList(args)));
}
}
Example:
# javac JoinDemo.java
# java JoinDemo a b c
a,b,c

Python-like list comprehension in Java

Since Java doesn't allow passing methods as parameters, what trick do you use to implement Python like list comprehension in Java ?
I have a list (ArrayList) of Strings. I need to transform each element by using a function so that I get another list. I have several functions which take a String as input and return another String as output. How do I make a generic method which can be given the list and the function as parameters so that I can get a list back with each element processed. It is not possible in the literal sense, but what trick should I use ?
The other option is to write a new function for each smaller String-processing function which simply loops over the entire list, which is kinda not so cool.
In Java 8 you can use method references:
List<String> list = ...;
list.replaceAll(String::toUpperCase);
Or, if you want to create a new list instance:
List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
Basically, you create a Function interface:
public interface Func<In, Out> {
public Out apply(In in);
}
and then pass in an anonymous subclass to your method.
Your method could either apply the function to each element in-place:
public static <T> void applyToListInPlace(List<T> list, Func<T, T> f) {
ListIterator<T> itr = list.listIterator();
while (itr.hasNext()) {
T output = f.apply(itr.next());
itr.set(output);
}
}
// ...
List<String> myList = ...;
applyToListInPlace(myList, new Func<String, String>() {
public String apply(String in) {
return in.toLowerCase();
}
});
or create a new List (basically creating a mapping from the input list to the output list):
public static <In, Out> List<Out> map(List<In> in, Func<In, Out> f) {
List<Out> out = new ArrayList<Out>(in.size());
for (In inObj : in) {
out.add(f.apply(inObj));
}
return out;
}
// ...
List<String> myList = ...;
List<String> lowerCased = map(myList, new Func<String, String>() {
public String apply(String in) {
return in.toLowerCase();
}
});
Which one is preferable depends on your use case. If your list is extremely large, the in-place solution may be the only viable one; if you wish to apply many different functions to the same original list to make many derivative lists, you will want the map version.
The Google Collections library has lots of classes for working with collections and iterators at a much higher level than plain Java supports, and in a functional manner (filter, map, fold, etc.). It defines Function and Predicate interfaces and methods that use them to process collections so that you don't have to. It also has convenience functions that make dealing with Java generics less arduous.
I also use Hamcrest** for filtering collections.
The two libraries are easy to combine with adapter classes.
** Declaration of interest: I co-wrote Hamcrest
Apache Commons CollectionsUtil.transform(Collection, Transformer) is another option.
I'm building this project to write list comprehension in Java, now is a proof of concept in https://github.com/farolfo/list-comprehension-in-java
Examples
// { x | x E {1,2,3,4} ^ x is even }
// gives {2,4}
Predicate<Integer> even = x -> x % 2 == 0;
List<Integer> evens = new ListComprehension<Integer>()
.suchThat(x -> {
x.belongsTo(Arrays.asList(1, 2, 3, 4));
x.is(even);
});
// evens = {2,4};
And if we want to transform the output expression in some way like
// { x * 2 | x E {1,2,3,4} ^ x is even }
// gives {4,8}
List<Integer> duplicated = new ListComprehension<Integer>()
.giveMeAll((Integer x) -> x * 2)
.suchThat(x -> {
x.belongsTo(Arrays.asList(1, 2, 3, 4));
x.is(even);
});
// duplicated = {4,8}
You can use lambdas for the function, like so:
class Comprehension<T> {
/**
*in: List int
*func: Function to do to each entry
*/
public List<T> comp(List<T> in, Function<T, T> func) {
List<T> out = new ArrayList<T>();
for(T o: in) {
out.add(func.apply(o));
}
return out;
}
}
the usage:
List<String> stuff = new ArrayList<String>();
stuff.add("a");
stuff.add("b");
stuff.add("c");
stuff.add("d");
stuff.add("cheese");
List<String> newStuff = new Comprehension<String>().comp(stuff, (a) -> { //The <String> tells the comprehension to return an ArrayList<String>
a.equals("a")? "1":
(a.equals("b")? "2":
(a.equals("c")? "3":
(a.equals("d")? "4": a
)))
});
will return:
["1", "2", "3", "4", "cheese"]
import java.util.Arrays;
class Soft{
public static void main(String[] args){
int[] nums=range(9, 12);
System.out.println(Arrays.toString(nums));
}
static int[] range(int low, int high){
int[] a=new int[high-low];
for(int i=0,j=low;i<high-low;i++,j++){
a[i]=j;
}
return a;
}
}
Hope, that I help you :)

Categories

Resources