Variable initialization from intermediate result

Sometimes, when the source code gets complicated, I find it difficult to introduce statements like this:

Set<Integer> odds = new HashSet<>(ints); // not yet true
odds.removeAll(evens); // now it true

      

I was wondering if there is a clever way to avoid a string where odds

it even contains even values. Something similar to this:

(Set<Integer> odds = new HashSet<>(ints)).removeAll(evens); // doesn't compile

      

I could use double brace initialization,

Set<Integer> odds = new HashSet<Integer>(ints) {{ removeAll(evens); }};

      

but this is clearly bad for several reasons .

Here's another example that compiles but looks more like a joke:

Set<Integer> odds = (odds = new HashSet<>(ints)).retainAll(evens) ? odds : odds

      

The last one that came to my mind (while writing this) seems to be ok, although it uses two lines:

Set<Integer> odds;
(odds = new HashSet<Integer>(ints)).removeAll(evens);

      

Any other ideas?

+3


source to share


3 answers


Use a stream:

Set<Integer> odds =
    ints.stream().filter(x -> x % 2 == 1).collect(Collectors.toSet());

      



If you want to split the set into coefficients and alignments at the same time:

Map<Boolean, Set<Integer>> oddsAndEvens =
    ints.stream().collect(
        Collectors.partitioningBy(x -> x % 2 == 0, Collectors.toSet()));
Set<Integer> evens = oddsAndEvens.get(true);
Set<Integer> odds = oddsAndEvens.get(false);

      

+3


source


The problem with the other answer is that it only applies if there is a simple filter that you can use.

What happens if the contents of the sets are completely arbitrary and you want to create a new set with the result SetA - SetB

on one line?

Install substrate B

The best solution I can think of is to use the decorator pattern . We can easily wrap HashSet

and delegate all interface methods to Set

this object.

We now have a class that we can use for this purpose throughout our entire code.

class ReducedHashSet<E> implements Set<E>
{
    private final Set<E> wrapped;

    ReducedHashSet(Collection<? extends E> superset, Collection<?> subset)
    {
        // Yes, I know this is the same as you were doing in your example,
        // but now it both in the correct context and we've reduced how
        // often you will need to repeat yourself.

        wrapped = new HashSet<>(superset);
        wrapped.removeAll(subset);
    }

    // Delegated Set<E> methods
    public boolean  add(E e)                          { return wrapped.add(e);         }
    public boolean  addAll(Collection<? extends E> c) { return wrapped.addAll(c);      }
    public void     clear()                           { wrapped.clear();               }
    public boolean  contains(Object o)                { return wrapped.contains(o);    }
    public boolean  containsAll(Collection<?> c)      { return wrapped.containsAll(c); }
    public boolean  equals(Object o)                  { return wrapped.equals(o);      }
    public int      hashCode()                        { return wrapped.hashCode();     }
    public boolean  isEmpty()                         { return wrapped.isEmpty();      }
    public Iterator<E> iterator()                     { return wrapped.iterator();     }
    public boolean  remove(Object o)                  { return wrapped.remove(o);      }
    public boolean  removeAll(Collection<?> c)        { return wrapped.removeAll(c);   }
    public boolean  retainAll(Collection<?> c)        { return wrapped.retainAll(c);   }
    public int      size()                            { return wrapped.size();         }
    public Object[] toArray()                         { return wrapped.toArray();      }
    public <T> T[]  toArray(T[] a)                    { return wrapped.toArray(a);     }

    // Delegated Object methods
    public String   toString()                        { return wrapped.toString();     }
    /* And do the other Object methods too... */
}

      

And then use it like this:



Set<Integer> odds = new ReducedHashSet<>(ints, evens);

      


Alternatively, a much less object oriented way to do this is to use a static method. This is also very similar to your first example, but without the "lies".

private static <T> Set<T> removeFromSet(final Set<T> set, final Collection<T> remove)
{
    set.removeAll(remove);
    return set;
}

      

Use it like this:

Set<Integer> odds = removeFromSet(new HashSet<>(ints), evens);

      

-2


source


I'm not sure why you are trying to complicate this question. If you can get a collection evens

, you can do the same for odds

.

Then you can simply do:

Set<Integer> oddsSet = new HashSet<>(odds);

      

Alternatively, you can condense your last example into one line:

Set<Integer> odds; (odds = new HashSet<Integer>(ints)).removeAll(evens);

      

I apologize for my ignorance, but I think this problem is academic, and the other suggested answers may not necessarily compensate for the lack of an extra line at all costs, for example using streams will almost certainly be worse than a genuine collection.

-2


source







All Articles