How to copy a Set<Set<Integer>> into a List<Integer[]> in Java?

Viewed 334

I want to copy a Set<Set<Integer>> of array to a List of Integer[]. I want to do that because I want to change the first element of every array when it is 0 , and put it at the end.

I have manage to do that but in a List<Set> , and when looping throw , I can't make changes because the array are still a Set.

No other questions make this clear, instead they explained when we have only Set<SomeWrapperClass>

Maybe some other solutions? Remark: I cannot change the Set<Set<Integer>>

My Set:

Set<Set<Integer>> indexs = new HashSet<>();

I can convert to a List only in this way:

List<Set<Integer>> arrangedIndexOfCourses = new ArrayList<>();

 static Set<Set<Integer>> coursesIndex = Sets.powerSet(Sets.newHashSet(1, 2, 3, 4, 5, 6, 7, 8, 9, 0));
  static List<Set<Integer>> arrangedIndexOfCourses = new ArrayList<>();

The following method return all the occurence of unique numbers made from 0123456789 ( Guava library )

 private void indexSet(Set<Set<Integer>> coursesIndex) {
        Set<Set<Integer>> indexs = new HashSet<>();
        for (Set<Integer> token : coursesIndex) {
            indexs.add(token);
            arrangedIndexOfCourses.add(token);
            count++;
        }
    }

And the code where I tried to change the first 0 of the arrays and put at last:

  for (Set<Integer> i : arrangedIndexOfCourses) {
                if (i.contains(0)) {
                   Collections.rotate(arrangedIndexOfCourses, -1);
                }
            }
2 Answers

It appears, the main trick in this task is how to implement rotation of the first element if it is 0.

As mentioned in the comments, not all types of sets maintain order and therefore have a "first" element. But upon converting a set to stream, even for a HashSet there's a first element in the stream unless it's empty.

Therefore, the set of integer sets may be converted to a list of integer arrays as follows:

  1. Take the first element of the stream using limit or findFirst
  2. Compare to 0, if needed put it to the end
  3. Else keep the stream of the set as is
Set<Set<Integer>> data = Set.of(
    Collections.emptySet(),
    new LinkedHashSet<>(Arrays.asList(0, 1, 2, 3)),
    new LinkedHashSet<>(Arrays.asList(4, 5, 6)),
    new LinkedHashSet<>(Arrays.asList(10, 0, 100, 1000)),
    new TreeSet<>(Arrays.asList(25, 0, 1, 16, 4, 9)),
    new HashSet<>(Arrays.asList(0, 5, 50))
);
      
List<Integer[]> rotatedZeros = data
    .stream()
    .map(s -> 
        (s.stream().findFirst().orElse(-1) == 0 // or limit(1).findAny()
            ? Stream.concat(s.stream().skip(1), Stream.of(0))
            : s.stream())
        .toArray(Integer[]::new)
    )
    .collect(Collectors.toList());

rotatedZeros.stream().map(Arrays::toString).forEach(System.out::println);

Output:

[]
[4, 5, 6]
[1, 2, 3, 0]
[10, 0, 100, 1000]
[1, 4, 9, 16, 25, 0]
[50, 5, 0]

the 2-step solution with a lambda w/o external library

(1) convert the Set<Set<Integer>> to a List<Integer[]>

List<Integer[]> arrangedIndexOfCourses = coursesIndex.stream()
    .map(s -> s.toArray(Integer[]::new)).collect(toList());

(2) iterate over the arrays and change the zero-arrays in the traditional way

for (Integer[] indices : arrangedIndexOfCourses) {
  if (indices.length > 0 && indices[0] == 0) {
    for (int i = 0; i < indices.length - 1; i++)
      indices[i] = indices[i + 1];
    indices[indices.length - 1] = 0;
  }
}



a lambda based on Alex's mind blowing solution
moving the zero-rotating-stuff upstream makes the lambda less trickier and You can work with collections instead of arrays

List<Integer[]> arrangedIndexOfCourses = coursesIndex.stream()
    .map(s -> {
      if (s.stream().findFirst().orElse(-1) == 0) {
        List<Integer> l = new ArrayList<>();
        l.addAll(s);
        l.remove(0);
        l.add(0);
        return l.toArray(Integer[]::new);
      } else
        return s.toArray(Integer[]::new);
    }).collect(toList());
Related