Problem overview
PriceList gets a List<string> named items and a List<int> named prices of the same length. The price at each index belongs to the item at the same index. It returns a List<string> with one line per item, in the form "1. apple: 3": the item's number starting at 1, a dot and a space, the item, a colon and a space, then its price.
For ["apple", "bread", "milk"] and [3, 2, 4] the result is ["1. apple: 3", "2. bread: 2", "3. milk: 4"]. The same item may repeat, as in ["pen", "pen", "ink"] with [2, 3, 0], and each copy gets its own line, number and price.
Approach: pair first, then number
Two ideas fit together here, and each has its own LINQ method.
items.Zip(prices, (item, price) => ...)walks the two lists side by side, so each item meets its own price. The lambda builds one string,item + ": " + price.Select((entry, i) => ...)can see each entry's indexi. Starting from 0, the line's number isi + 1.
Doing the pairing first leaves lines like apple: 3. The numbering step then puts 1. in front of each. Both methods return sequences, so each ends with ToList().
Step by step
- Build
entries, aList<string>, fromitems.Zip(prices, ...)with a lambda overitemandprice, thenToList(). - Return the numbered lines:
entries.Select((entry, i) => (i + 1) + ". " + entry).ToList().
The solution in C#
class Solution {
public List<string> PriceList(List<string> items, List<int> prices) {
List<string> entries = items.Zip(prices, (item, price) => item + ": " + price).ToList();
return entries.Select((entry, i) => (i + 1) + ". " + entry).ToList();
}
}
In item + ": " + price, the string on the left makes + join text, so the int price is turned into text automatically. In (i + 1) + ". " + entry, the parentheses make i + 1 add numbers first, and the result becomes text when it meets ". ". The parentheses are optional here, since + works from left to right and i + 1 is added first anyway, but they make the intent clear.
Keep the order of the two steps in mind. If the numbering came first, the lines would be 1. apple and the price would still need to be attached, which means looking it up by index. Pairing first gives each line everything except its number, and the number depends only on the line's position, which is exactly what the index in Select provides.
Complexity
Each step makes one pass over the n items, so the time is O(n) and the extra space is O(n) for the lists of lines.
Another way
You can number the items and read the price by index in one Select: items.Select((item, i) => (i + 1) + ". " + item + ": " + prices[i]).ToList(). It gives the same lines for the first example. The lesson's version avoids indexing prices[i] by hand, and Zip makes the pairing of the two lists explicit.
Testing
Outputs from running the solution:
| items, prices | Result |
|---|---|
["apple", "bread", "milk"], [3, 2, 4] | [1. apple: 3, 2. bread: 2, 3. milk: 4] |
["tea"], [5] | [1. tea: 5] |
["pen", "pen", "ink"], [2, 3, 0] | [1. pen: 2, 2. pen: 3, 3. ink: 0] |
Common mistakes
- Starting the numbers at 0. The index is zero-based, so the number is
i + 1. - Using a dictionary from item to price. It fails with repeated items such as the two pens. Two lists matched by position handle them.
- Forgetting
ToList(). BothZipandSelectreturn sequences. The method's return type isList<string>, so the last call in the chain must end withToList(). The lesson also ends the first one with it, soentriesis a real list.
