How to copy a part of an ArrayList, change and add to the same ArrayList?

Viewed 123

I will create an ArrayList to which I will add 5 elements.

// This is just an example
var rectangles = new ArrayList<>(20) {
    {
        add(new Rectangle(10, 10, Color.RED));
        add(new Rectangle(20, 20, Color.GREEN));
        add(new Rectangle(30, 30, Color.YELLOW));
        add(new Rectangle(40, 40, Color.BLUE));
        add(new Rectangle(50, 50, Color.PURPLE));
    }
};

The remaining 15 elements don't need to be written, because the first five will only be repeated, but each five will have a specific property set.

It is better to see it on the code.

for (var angle = 90; angle <= 270; angle += 90) {
    var part_of_array = rectangles.subList(0, 5);
    var rotate = new Rotate(angle, 500, 500);
    part_of_array.stream().forEach(t -> ((Rectangle) t).getTransforms().add(rotate));  
    rectangles.addAll(part_of_array);
}

But the code is complicated and, most importantly, doesn't work at all. As a result, the array has 20 elements, but they all have an angle set to 90.

How to write it correctly, please?

Thank you

2 Answers

I would use Streams for that job:

Option 1:

List<Rectangle> rectangles = Stream.of(new Rectangle(10, 10, Color.RED),
                                        new Rectangle(20, 20, Color.GREEN),
                                        new Rectangle(30, 30, Color.YELLOW),
                                        new Rectangle(40, 40, Color.BLUE),
                                        new Rectangle(50, 50, Color.PURPLE))
    .flatMap(rectangle -> 
            IntStream.range(0, 4).mapToObj(i -> {
                var newRectangle = new Rectangle(rectangle.getWidth(), rectangle.getHeight(), rectangle.getFill());
                newRectangle.getTransforms().add(new Rotate(90 * i, 500, 500));
                return newRectangle;
            }))
    .collect(Collectors.toList());

Option 2:

Given that your rectangles are squares (height == width), you can also do:

Map<Integer, Color> map = Map.of(10, Color.RED, 20, Color.GREEN, 30, Color.YELLOW, 40, Color.BLUE, 50, Color.PURPLE);

List<Rectangle> rectangles = map.entrySet().stream()
    .flatMap(entry -> IntStream.range(0, 4).mapToObj(i -> {
            Rectangle rectangle = new Rectangle(entry.getKey(), entry.getKey(), entry.getValue());
            rectangle.getTransforms().add(new Rotate(90 * i, 500, 500));
            return rectangle;
        }))
    .collect(Collectors.toList());

Update

Option 1:

To maintain the order you need to use Comparator and invert the streams.

List<Rectangle> rectangles = IntStream.range(0, 4).boxed()
    .flatMap(i -> 
        Stream.of(new Rectangle(10, 10, Color.RED),
                    new Rectangle(20, 20, Color.GREEN),
                    new Rectangle(30, 30, Color.YELLOW),
                    new Rectangle(40, 40, Color.BLUE),
                    new Rectangle(50, 50, Color.PURPLE))
        .sorted(Comparator.comparingDouble(Rectangle::getWidth))
        .map(rectangle -> {
            var newRectangle = new Rectangle(rectangle.getWidth(), rectangle.getHeight(), rectangle.getFill());
            newRectangle.getTransforms().add(new Rotate(90 * i, 500, 500));
            return newRectangle;
        }))
    .collect(Collectors.toList());

Option 2:

To maintain the order you need to use a TreeMap and invert the streams.

Map<Integer, Color> map = Map.of(10, Color.RED, 20, Color.GREEN, 30, Color.YELLOW, 40, Color.BLUE, 50, Color.PURPLE);

Map<Integer, Color> treeMap = new TreeMap<>(map);

List<Rectangle> rectangles = IntStream.range(0, 4).boxed()
    .flatMap(i -> 
        treeMap.entrySet().stream().map(entry -> {
                Rectangle rectangle = new Rectangle(entry.getKey(), entry.getKey(), entry.getValue());
                rectangle.getTransforms().add(new Rotate(90 * i, 500, 500));
                return rectangle;
        }))
    .collect(Collectors.toList());

You need to create a new list from the sublist to avoid altering the initial list and you need to clone each rectangle:

var part_of_array = new ArrayList<Rectangle>(rectangles.subList(0, 5));
var rotate = new Rotate(angle, 500, 500);
part_of_array.stream().forEach(t -> ((Rectangle) t.clone()).getTransforms().add(rotate));  
rectangles.addAll(part_of_array);
Related