code: package zemberek.core.collections;
  
  import java.io.IOException;
  import java.nio.file.Path;
  import java.util.List;
  import zemberek.core.StringPair;
  import zemberek.core.text.TextIO;
  
  public class BidirectionalIndexLookup<T> {
  
    UIntValueMap<T> indexLookup;
    UIntMap<T> keyLookup;
  
    public BidirectionalIndexLookup(UIntValueMap<T> indexLookup, UIntMap<T> keyLookup) {
      this.indexLookup = indexLookup;
      this.keyLookup = keyLookup;
    }
  
    public static BidirectionalIndexLookup<String> fromTextFileWithIndex(Path path, char delimiter)
        throws IOException {
      if (!path.toFile().exists()) {
        throw new IllegalArgumentException("File " + path + " does not exist.");
      }
      List<String> lines = TextIO.loadLines(path);
      UIntValueMap<String> indexLookup = new UIntValueMap<>(lines.size());
      UIntMap<String> wordLookup = new UIntMap<>(lines.size());
      for (String line : lines) {
        StringPair pair = StringPair.fromString(line, delimiter);
        String word = pair.first;
        int index = Integer.parseInt(pair.second);
        if (indexLookup.contains(word)) {
          throw new IllegalArgumentException("Duplicated word in line : [" + line + "]");
        }
        if (wordLookup.containsKey(index)) {
          throw new IllegalArgumentException("Duplicated index in line : [" + line + "]");
        }
        if (index < 0) {
          throw new IllegalArgumentException("Index Value cannot be negative : [" + line + "]");
        }
        indexLookup.put(word, index);
        wordLookup.put(index, word);
      }
      return new BidirectionalIndexLookup<>(indexLookup, wordLookup);
    }
  
    public int getIndex(T key) {
      return indexLookup.get(key);
    }
  
    public T getKey(int index) {
      return keyLookup.get(index);
    }
  
    public boolean containsKey(T key) {
      return indexLookup.contains(key);
    }
  
    public Iterable<T> keys() {
      return indexLookup.getKeyList();
    }
  
    public int size() {
      return indexLookup.size();
    }
  }
  