/* package whatever; // don't place package name! */

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

 class ArrayBenchmark {
  public static void main(String[] args) {
    List<Integer> arraySizes = Arrays.asList(1, 5, 10, 20,50,60,80, 100,200,500, 1000,2000, 5000,10000);
    int numberOfSamples = 200;
    Map<Integer, List<int[]>> arraysBySize = new TreeMap<>();
    Map<Integer, List<Long>> runTimesBySize = new TreeMap<>();
    arraySizes.forEach(size -> {
      System.out.printf("Initializing arrays for size %d%n", size);
      List<int[]> arrays = new ArrayList<>();
      List<Long> runtimes = new ArrayList<>();
      for (int j = 0; j < numberOfSamples; j++) {
        int[] arr = new int[size];
        for (int i = 0; i < size; i++) {
          arr[i] = i;
        }
        arrays.add(arr);
      }
      arraysBySize.put(size, arrays);
      runTimesBySize.put(size, runtimes);
    });

    arraysBySize.entrySet().forEach(entry -> {
      int size = entry.getKey();
      System.out.printf("Running Benchmark for size %d%n", size);
      List<int[]> listOfArrays = entry.getValue();
      List<Long> runtimeList = runTimesBySize.get(size);
      for (int i = 0; i < numberOfSamples; i++) {
        int[] array = listOfArrays.get(i);
        int[] target = new int[array.length];
        long before = System.nanoTime();
        System.arraycopy(array, 0, target, 0, array.length);
        long after = System.nanoTime();
        runtimeList.add(after - before);
      }

    });

    System.out.println("Results:");
    System.out.println();

    runTimesBySize.forEach((size, runtimes) -> {

      System.out.printf("Array size: %d%n", size);
      System.out.printf("Total nanos: %d%n", runtimes.stream().mapToLong(Long::longValue).sum());
      System.out.printf("Average nanos: %s%n",
        runtimes.stream().mapToLong(Long::longValue).average().getAsDouble());
      
      System.out.println();
    });
  }
}