Count Items Matching a Rule
Description
You are given an array items, where items[i] = [type_i, color_i, name_i] describes the type, the color and the name of item i. You are also given a rule made of two strings, ruleKey and ruleValue.
Item i matches the rule when one of these is true:
ruleKey == "type"andruleValue == type_i;ruleKey == "color"andruleValue == color_i;ruleKey == "name"andruleValue == name_i.
Return the number of items that match the rule.
Examples
Example 1
Input: items = [["phone", "black", "pixel"], ["laptop", "silver", "thinkpad"], ["phone", "silver", "iphone"], ["tablet", "black", "ipad"]], ruleKey = "color", ruleValue = "silver"
Output: 2
Explanation: Only the colors are compared. Items 1 and 2 are silver; items 0 and 3 are black.
Example 2
Input: the same items, ruleKey = "name", ruleValue = "ipad"
Output: 1
Explanation: Only item 3 is named ipad.
Example 3
Input: the same items, ruleKey = "name", ruleValue = "silver"
Output: 0
Explanation: "silver" appears in the items, but only as a color. The rule asks for items named silver, and there are none.
Constraints
- 1 ≤ items.length ≤ 10^4
- 1 ≤ type_i.length, color_i.length, name_i.length, ruleValue.length ≤ 10
- ruleKey is "type", "color" or "name".
- All the strings consist only of lowercase letters.
Editorial
Brute Force
Intuition
Go through the items one by one and apply the rule exactly as it is written. If the key is "type", compare the item's type with the value; otherwise, if the key is "color", compare its color; otherwise, if the key is "name", compare its name. Each time a comparison is equal, add 1 to the count.

Only the chosen field counts. The value has to match in the field the key names. In Example 3, "silver" does appear in the items, but only as a color, so a rule asking for the name "silver" matches nothing.
Comparing strings. In Python and C++, == on two strings compares their letters. In Java it does not: == asks whether the two variables point to the very same string object, and a string read from the input is a different object from ruleValue even when the letters are the same. On a real run, comparing two strings that both spell silver gives false with == and true with .equals. Always compare strings with .equals in Java.
Reading items without copying (C++). for (const auto& item : items) looks at each item where it is. Writing for (auto item : items) would copy the item, all three strings, on every round.
Step-by-Step Explanation
We trace Example 1, where the rule is color = silver. The top row is the item being checked, with its fields named underneath; its color is green when it equals silver and orange when it does not.
Step 1: The rule is ruleKey = "color", ruleValue = "silver". count starts at 0.
Step 2: Item 0 (phone, black, pixel): 3 questions about the key, then black is not "silver". count stays 0.
Step 3: Item 1 (laptop, silver, thinkpad): 2 questions about the key, then silver equals "silver", so count = 1.
Step 4: Item 2 (phone, silver, iphone): 2 questions about the key, then silver equals "silver", so count = 2.
Step 5: Item 3 (tablet, black, ipad): 3 questions about the key, then black is not "silver". count stays 2.
Step 6: Return 2, after 10 questions about a key that never changed.
Brute Force — Ask Which Key, for Every Item — Example 1, rule color = silver. Each item is shown with its fields named underneath; the if-chain asks about the key again for every item.
Algorithm
- Set
count = 0. - For each item
[type, color, name]:- if
ruleKey == "type"andtype == ruleValue, add 1 tocount; - otherwise, if
ruleKey == "color"andcolor == ruleValue, add 1; - otherwise, if
ruleKey == "name"andname == ruleValue, add 1.
- if
- Return
count.
Code
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
int countMatches(vector<vector<string>>& items, string ruleKey, string ruleValue) {
int count = 0;
for (const auto& item : items) { // by reference: copying an item would copy its three strings
if (ruleKey == "type" && item[0] == ruleValue) count++;
else if (ruleKey == "color" && item[1] == ruleValue) count++;
else if (ruleKey == "name" && item[2] == ruleValue) count++;
}
return count;
}
};class Solution:
def countMatches(self, items: list[list[str]], ruleKey: str, ruleValue: str) -> int:
count = 0
for item_type, color, name in items:
if ruleKey == 'type' and item_type == ruleValue:
count += 1
elif ruleKey == 'color' and color == ruleValue:
count += 1
elif ruleKey == 'name' and name == ruleValue:
count += 1
return countimport java.util.List;
class Solution {
public int countMatches(List<List<String>> items, String ruleKey, String ruleValue) {
int count = 0;
for (List<String> item : items) { // equals compares the letters; == would compare which object it is
if (ruleKey.equals("type") && item.get(0).equals(ruleValue)) count++;
else if (ruleKey.equals("color") && item.get(1).equals(ruleValue)) count++;
else if (ruleKey.equals("name") && item.get(2).equals(ruleValue)) count++;
}
return count;
}
}Complexity Analysis
Let n be the number of items and L the length of the strings, at most 10.
Time Complexity: O(n · L). Each item costs up to three questions about the key and one comparison of the value, and comparing two strings takes up to L steps.
Space Complexity: O(1).
Why This Approach Is Not Efficient
The answer to "which field does the rule name?" is the same for every item, yet the if-chain asks it again for each one, up to three questions per item. On Example 1 that is 10 questions about the key for 4 items. The growth is already the best possible, O(n), so this is not about big-O: it is repeated work inside the loop. Measured in Python on 10,000 items, it takes 0.155 ms, against 0.071 ms when the key is settled once before the loop.
The key only decides which of an item's three positions to read, and that can be worked out once.
Optimal Approach - Decide the Column Once
Intuition
Turn the key into a position, once. An item is a list of three strings in a fixed order: the type at position 0, the color at position 1, the name at position 2. So the key simply names a position. Look it up before the loop, with a small dictionary in Python, {'type': 0, 'color': 1, 'name': 2}, or a short chain of comparisons in C++ and Java. After that, every item needs just one comparison, item[column] == ruleValue.

This pattern, working out before a loop anything that does not change inside it, is worth making a habit. Here it removes every question about the key and leaves the loop doing only the work that really differs from item to item.
In one line. Python can count with sum(1 for item in items if item[column] == ruleValue), and Java streams can do the same with filter and count. The plain loop below does exactly the same work and reads the same in all three languages.
Step-by-Step Explanation
We trace Example 1 again. The first frame turns the key into a position; after that each item needs one comparison, green when it equals silver and orange when it does not.
Step 1: Before the loop: "color" is at position 1, so column = 1.
Step 2: Item 0: item[1] is black, not a match. count stays 0.
Step 3: Item 1: item[1] is silver, a match, so count = 1.
Step 4: Item 2: item[1] is silver, a match, so count = 2.
Step 5: Item 3: item[1] is black, not a match. count stays 2.
Step 6: Return 2, with the key looked up once.
Decide the Column Once, Then One Comparison per Item — Example 1, rule color = silver. The key becomes a position before the loop; each item then needs a single comparison.
Algorithm
- Set
columnto 0, 1 or 2 whenruleKeyis "type", "color" or "name". - Set
count = 0. For each item, add 1 tocountifitem[column] == ruleValue. - Return
count.
In Java, still .equals, not ==. The position is decided once, but the comparison of the value is still between two different string objects.
Code
#include <string>
#include <vector>
using namespace std;
class Solution {
public:
int countMatches(vector<vector<string>>& items, string ruleKey, string ruleValue) {
int column = ruleKey == "type" ? 0 : ruleKey == "color" ? 1 : 2; // decided once: it is the same for every item
int count = 0;
for (const auto& item : items)
if (item[column] == ruleValue) count++;
return count;
}
};class Solution:
def countMatches(self, items: list[list[str]], ruleKey: str, ruleValue: str) -> int:
column = {'type': 0, 'color': 1, 'name': 2}[ruleKey] # decided once: it is the same for every item
count = 0
for item in items:
if item[column] == ruleValue:
count += 1
return countimport java.util.List;
class Solution {
public int countMatches(List<List<String>> items, String ruleKey, String ruleValue) {
int column = ruleKey.equals("type") ? 0 : ruleKey.equals("color") ? 1 : 2; // decided once: it is the same for every item
int count = 0;
for (List<String> item : items)
if (item.get(column).equals(ruleValue)) count++;
return count;
}
}Complexity Analysis
Time Complexity: O(n · L), one string comparison per item. Measured in Python, 0.071 ms for 10,000 items.
Space Complexity: O(1).
No method can do less. An item that is never checked could be a match, so every item has to be looked at, and n comparisons is the least any method can make.