@Override
    public Projection difference(Projection other) {
      if (other.isNested()) {
        throw new IllegalArgumentException(
            "Cannot perform difference between nested projection and nested projection");
      }
      if (other instanceof EmptyProjection) {
        return this;
      }
      if (!this.isNested()) {
        return new TopLevelProjection(toTopLevelIndexes()).difference(other);
      }

      // Extract the indexes to exclude and sort them
      int[] indexesToExclude = other.toTopLevelIndexes();
      indexesToExclude = Arrays.copyOf(indexesToExclude, indexesToExclude.length);
      Arrays.sort(indexesToExclude);

      List<int[]> resultProjection =
          Arrays.stream(projection).collect(Collectors.toCollection(ArrayList::new));

      ListIterator<int[]> resultProjectionIterator = resultProjection.listIterator();
      while (resultProjectionIterator.hasNext()) {
        int[] indexArr = resultProjectionIterator.next();

        // Let's check if the index is inside the indexesToExclude array
        int searchResult = Arrays.binarySearch(indexesToExclude, indexArr[0]);
        if (searchResult >= 0) {
          // Found, we need to remove it
          resultProjectionIterator.remove();
        } else {
          // Not found, let's compute the offset.
          // Offset is the index where the projection index should be inserted in the
          // indexesToExclude array
          int offset = (-(searchResult) - 1);
          if (offset != 0) {
            indexArr[0] = indexArr[0] - offset;
          }
        }
      }

      return new NestedProjection(resultProjection.toArray(new int[0][]));
    }
Create a {@link Projection} of a field range.
amoro-format-mixed/amoro-mixed-flink/amoro-mixed-flink-common/src/main/java/org/apache/amoro/flink/util/Projection.java