private getFoodEntries(): Map<number, Set<string>> {
    // Reduce over the second through last line, converting the string into a
    // Map of {price: ["set", "of", "foods", "at", "that", "price"]}
    return this.lines
      .slice(1) // drop the first line, which contains desiredPrice
      .reduce(
      (accum, el: string): Map<number, Set<string>> => {

        // parseOneLine returns a single-entry Map. {price: ["food", "food"]}.
        let newEntry = this.parseOneLine(el);

        // mergeWith merges two maps. If there is a collision between keys, it
        // calls the passed-in function, and sets the value at that key
        // as the value returned from the lambda. Here, if the keys collide, we
        // know we must concat the food name to the list of food names already
        // at that price.
        return accum.mergeWith((oldVal, newVal) => {
          return oldVal.concat(newVal);
        }, newEntry);
      }, Map()) as Map<number, Set<string>>;
  }