code: public static <T, E extends Exception> List<T> distinctBy(final Collection<? extends T> c, final int fromIndex, final int toIndex,
              final Try.Function<? super T, ?, E> keyMapper) throws E {
          checkFromToIndex(fromIndex, toIndex, size(c));
  
          if (N.isNullOrEmpty(c) && fromIndex == 0 && toIndex == 0) {
              return new ArrayList<>();
          }
  
          final List<T> result = new ArrayList<>();
          final Set<Object> set = new HashSet<>();
          T e = null;
  
          if (c instanceof List && c instanceof RandomAccess) {
              final List<T> list = (List<T>) c;
  
              for (int i = fromIndex; i < toIndex; i++) {
                  e = list.get(i);
  
                  if (set.add(hashKey(keyMapper.apply(e)))) {
                      result.add(e);
                  }
              }
          } else {
              final Iterator<? extends T> it = c.iterator();
  
              for (int i = 0; i < toIndex && it.hasNext(); i++) {
                  e = it.next();
  
                  if (i < fromIndex) {
                      continue;
                  }
  
                  if (set.add(hashKey(keyMapper.apply(e)))) {
                      result.add(e);
                  }
              }
          }
  
          return result;
      }
docs: Distinct by the value mapped from <code>keyMapper</code>.
  
  Mostly it's designed for one-step operation to complete the operation in one step.
  <code>java.util.stream.Stream</code> is preferred for multiple phases operation.
  
  @param c
  @param fromIndex
  @param toIndex
  @param keyMapper don't change value of the input parameter.
  @return