<commit_before>// @flow
import {isEmpty, isArray, isNil, get, map, filter, includes} from "lodash";

import type {RuleOptions} from "../types";

function duplicateValuesExist(array): boolean {
  return !isEmpty(filter(array, (value, index, item) => includes(item, value, index + 1)));
}

export default function uniqueInArray(
  field: string,
  array: ?Array<mixed>,
  options?: RuleOptions,
): ?string {
  if (!isArray(array)) {
    return "uniqueInArray";
  }

  const byUniqueObjectKey = get(options, "byKey");
  if (!isNil(byUniqueObjectKey) && duplicateValuesExist(map(array, byUniqueObjectKey))) {
    return "uniqueInArray.byKey";
  }

  if (duplicateValuesExist(array)) {
    return "uniqueInArray";
  }

  return null;
}<commit_msg>perf: Use seen object pattern in unique check instead of double filtering<commit_after>// @flow
import {isArray, isNil, get, map} from "lodash/fp";

import type {RuleOptions} from "../types";

function duplicateValuesExist<T>(array: Array<T>): boolean {
  const seen: {[key: T]: boolean} = {};
  for (let i = 0; i < array.length; i += 1) {
    if (seen[array[i]]) {
      return true;
    }
    seen[array[i]] = true;
  }
  return false;
}

export default function uniqueInArray(
  field: string,
  array: ?Array<mixed>,
  options?: RuleOptions,
): ?string {
  if (!isArray(array)) {
    return "uniqueInArray";
  }

  const byUniqueObjectKey: ?string = get("byKey")(options);
  if (!isNil(byUniqueObjectKey)) {
    if (duplicateValuesExist(map(byUniqueObjectKey)(array))) {
      return "uniqueInArray.byKey";
    }
    // $FlowFixMe
  } else if (duplicateValuesExist(array)) {
    return "uniqueInArray";
  }

  return null;
}
{'fraction_non_alphanumeric': 0.1502994011976048, 'fraction_numerical': 0.0017964071856287425, 'mean_word_length': 4.271293375394322, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6407913', 'n_tokens_mistral': 558, 'n_tokens_neox': 547, 'n_words': 143}