简体   繁体   中英

How to create a new list and add a value in single statement

What I'm trying to achieve is probably quite pointless but I would like to find this out to satisfy my curiosity.

I'm trying to create a single efficient statement that would create a new list based on another and add a new value to the end.

I'm new to lambda expressions and I'm not sure what kind of list should I be using for this.

the method would look something like this:

private List<Integer> conjoin(List<Integer> list, Integer newValue){
    return new ArrayList<Integer>(list).stream()
            .map(value -> list.indexOf(value)==(list.size()-1) ? 
                    Arrays.asList(value, newValue) : 
                    Arrays.asList(value))
            .flatMap(Collection::stream)
            .collect(Collectors.toList());        
}

but more neat and efficient.

Or is there a built-in method doing the same that I didn't know about?

I love one-liners as much as anyone else, but they come with a cost - namely they're harder to read than being explicit. So lets start with the "normal" way to do what you're describing:

ArrayList<E> copy = new ArrayList<>(list);
copy.add(value);
return copy;

It's a few lines, but it's efficient, straight-forward, and easy to read. We want any alternative to be an improvement on this syntax, not simply replacing readability for conciseness. If you're trying to decide between the implementation you've posted and the "normal" version, the "normal" version should win hands down.


We can try to improve on your solution with Stream.concat() and Stream.of() .

return Stream.concat(list.stream(), Stream.of(value))
    .collect(Collectors.toList());

It's technically all one statement now, but we still need to split it over multiple lines to make it readable. It's also a lot more boilerplate than the standard implementation.


Instead we can use the builder pattern Guava provides for its Immutable collections :

return new ImmutableList.Builder<E>().addAll(list).add(value).build();

This is more concise, and conveys our intent nicely. This is how I would recommend implementing the behavior you describe (using Guava or by defining your own builder pattern ). Not only does it work for this specific use case, but it scales to any arbitrary combination of values and collections.


I think (it's hard to read :) ) your example actually replaces the last value of the list with your new value, rather than adding it to the end. If that's what you want, just use List.sublist() to truncate the last element from the list, eg:

list.sublist(0, list.size() - 1)

Use that anywhere I have list above to exclude the last value.

One option is using

List<Integer> newList = (List<Integer>)ListUtils.union(list1,Arrays.asList(5));

From Apache Commons Collections . I understand that internally this is not "one single statement", but that's such an useful library that chances are a lot of people will have it anyway.


Example

// Your list
ArrayList<Integer> myList = new ArrayList<Integer>();
myList.add(2);

// Create new list with new element
List<Integer> newList = (List<Integer>)ListUtils.union(myList,Arrays.asList(5));

You can try this

 private List<Integer> conjoin(List<Integer> list, final Integer newValue){
      ArrayList<Integer> returnlist = new ArrayList<Integer>(list) {{
            add(newValue);
        }};
    return returnlist;
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM