10

I have 2 sets:

Set<String> set1 = new TreeSet<String>();
Set<String> set2 = new TreeSet<String>();
Set<String> set3 = new TreeSet<String>();

set1 = [A, C, E];
set2 = [B, D, F];

I am looking for a way to append the value of set2 to set1 and store them in set3

Set 3 Output

set3 = [AB, CD, EF]
Tunaki
  • 132,869
  • 46
  • 340
  • 423
Moe
  • 1,427
  • 4
  • 34
  • 54
  • You can not append elements to a set, because sets do not have a defined order. Do you mean "add" rather than append? – Raedwald Feb 04 '16 at 10:55
  • TreeSet Order its elements. Think of this as adding the entire set as a new column of data to an existing data in another set. – Moe Feb 04 '16 at 11:17

4 Answers4

16

You need to use an Iterator to keep the order of the TreeSet. You can get it by calling TreeSet.iterator():

Returns an iterator over the elements in this set in ascending order.

Assuming that both sets have the same length, you could have:

public static void main(String[] args) {
    Set<String> set1 = new TreeSet<String>(Arrays.asList("A", "C", "E"));
    Set<String> set2 = new TreeSet<String>(Arrays.asList("B", "D", "F"));
    Set<String> set3 = new TreeSet<String>();

    Iterator<String> it1 = set1.iterator();
    Iterator<String> it2 = set2.iterator();
    while (it1.hasNext() && it2.hasNext()) {
        set3.add(it1.next() + it2.next());
    }

    System.out.println(set3); // prints "[AB, CD, EF]"
}

If the set have different size and that is an error, you could add the following check before the while loop:

if (set1.size() != set2.size()) {
    throw new IllegalArgumentException("Can't merge sets of different size");
}

For reference, you could make this using Java 8, using the zip utility from this answer:

Set<String> set3 = zip(set1.stream(), set2.stream(), String::concat)
                            .collect(Collectors.toCollection(TreeSet::new));
Community
  • 1
  • 1
Tunaki
  • 132,869
  • 46
  • 340
  • 423
  • 1
    don't you need to use the LinkedHashSet to preserve the insertion order intact. so when you loop elements are in place where you expect. (where elements this example do fine with treeset) – kuhajeyan Feb 03 '16 at 10:20
  • @kuhajeyan OP uses a `TreeSet` in their example so I don't think they want to keep insertion order but the natural ordering of the elements. – Tunaki Feb 03 '16 at 10:21
  • @kuhajeyan Actually no! TreeSet is ordered with natural ordering. So using a `LinkedHashSet` or a `TreeSet` in this case makes no difference: we are iterating in the natural ordering of the elements so also adding them in their natural ordering. – Tunaki Feb 03 '16 at 10:25
  • yep, natural ordered. – kuhajeyan Feb 03 '16 at 10:26
  • Thanks Tunaki, exactly what I was looking for. – Moe Feb 03 '16 at 11:27
7

Here's a way to do this the imperative way, with Java 7:

Set<String> set1 = new TreeSet<String>(Arrays.asList(new String[]{"A", "C", "E"}));
Set<String> set2 = new TreeSet<String>(Arrays.asList(new String[]{"B", "D", "F"}));
Set<String> set3 = new TreeSet<String>();

// Java 7: imperative
// edit: checking sizes beforehand
if (set1.size() != set2.size()) 
    throw new IllegalStateException("Sets aren't the same size!");
Iterator<String> iterator1 = set1.iterator();
Iterator<String> iterator2 = set2.iterator();
while (iterator1.hasNext()) {
    String s = iterator1.next();
    // assuming iterator2.hasNext() as sizes were checked previously
    s = s.concat(iterator2.next());
    set3.add(s);
}
System.out.println(set3);

Output

[AB, CD, EF]

Java 8 variant with functional idiom (a little ugly)

// Java 8: functional (but ugly)
Iterator<String> iterator2new = set2.iterator();
// edited, ensuring a `TreeSet` is returned
set3 = 
    set1
    .stream()
    .map((s) -> s.concat(iterator2new.next()))
    .collect(Collectors.toCollection(TreeSet::new));
System.out.println(set3);

Output

[AB, CD, EF]
Mena
  • 47,782
  • 11
  • 87
  • 106
  • 3
    The Java 8 way is not very nice yeah... It does not return a `TreeSet` also. It'd be better to make a proper `zip`. See my answer. – Tunaki Feb 03 '16 at 11:04
  • @Tunaki yes it's ugly and labelled as such... Couldn't find a better way without too many dependencies. Note that you can always wrap it in a `TreeSet` once retrieved though. – Mena Feb 03 '16 at 11:13
  • Thanks for providing both answers for Java 8 and 7. What made me chose this answer over Tunaki's is this answers adds the elements until it find a miss match in size. Where Tunaki's answer will check before it attempts and throw an exception if they are different in size. – Moe Feb 03 '16 at 11:26
  • @Moe np. Yes the later check wasn't brilliant but written in the spur of the moment, hence the later `//TODO` :) – Mena Feb 03 '16 at 11:27
  • 2
    The Java 8 approach is flawed. It suffices that someone call `.parallelStream()` to have weird results. Also there is no need to do `map(o -> o.toString())` as you already have a `Stream` at that point... – Alexis C. Feb 03 '16 at 12:46
  • @AlexisC. that's why I don't use `parallelStream()` and call it ugly, but yes you have a point. About the second mapping, not sure why I did this, removing now. – Mena Feb 03 '16 at 13:20
  • @BoristheSpider nicer, definitely. Thanks. – Mena Feb 03 '16 at 17:17
  • @Mena np. I'm still finding uses for all the `Collectors` provided. My new favourite is [`Collectors.mapping`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#mapping-java.util.function.Function-java.util.stream.Collector-). – Boris the Spider Feb 03 '16 at 17:19
  • @BoristheSpider interesting. I wish I'd use Java 8 more in real life :( – Mena Feb 03 '16 at 18:13
2

Another way to do this is to use a library that adds zip to Java 8 streams such as https://github.com/poetix/protonpack or https://github.com/jOOQ/jOOL

Simon
  • 6,293
  • 2
  • 28
  • 34
0

I quite dislike while (it1.hasNext()), so my ways:

1)

    Iterator<String> iterator2 = set2.iterator();
    for(String s : set1) {
            set3.add(s.concat(iterator2.next()));
    }
    System.out.println(set3);

2) or

    List<String> list = new ArrayList<String>(set2);
    int i = 0;
    for(String s : set1) {
            set3.add(s.concat(list.get(i)));
            i++;
    }
    System.out.println(set3);

3) (1) with check:

    Iterator<String> iterator2 = set2.iterator();
    for(String s : set1) {
        set3.add(s.concat(iterator2.hasNext()? iterator2.next(): ""));
    }
    System.out.println(set3);

4) (2) with check:

    List<String> list = new ArrayList<String>(set2);
    int i = 0;
    for(String s : set1) {
            set3.add(s.concat(list.size() > i? list.get(i): ""));
            i++;
    }
    System.out.println(set3);
Slava Vedenin
  • 58,326
  • 13
  • 40
  • 59