import pandas as pd import numpy as np score_method = "qty" columns = [ "mpn", "value", "voltage_min", "voltage_max", "tolerance-", "tolerance+", ] parts = { "C1": (None, 100e-9, 10, np.inf, None, None), "C1a": (None, 100e-9, 10, 10, None, None), "C2": (None, 100e-9, 16, np.inf, 0.20, 0.30), "C2a": (None, 100e-9, 16, np.inf, None, None), "C2b": (None, 100e-9, 12, np.inf, None, None), "C3": (None, 100e-9, 0, np.inf, None, None), "C4": (None, 10e-9, 10, np.inf, None, None), "C5": (None, 10e-9, 12, np.inf, None, None), } nominal = pd.DataFrame( [v for _, v in parts.items()], index=parts.keys(), columns=columns, ) actual = nominal.copy(deep=True) remaining = nominal.copy(deep=True) # add temporary columns remaining.insert(1, "matches", None, True) remaining.insert(2, "score", -np.inf, True) remaining.insert(3, "match_mpn", None, True) # determine matches for idx, row in remaining.iterrows(): matches = [] for ii, rr in remaining.iterrows(): if (ii == idx) or ( (rr["value"] == row["value"]) and (rr["voltage_min"] <= row["voltage_min"]) and (rr["voltage_max"] >= row["voltage_max"]) ): matches.append(ii) remaining["matches"][idx] = matches n = 0 while len(remaining.index) > 0: for idx, row in remaining.iterrows(): if score_method == "qty": # score by qty remaining["score"][idx] = len(remaining["matches"][idx]) else: # score by price reduction pass best_idx = remaining["score"].idxmax() best_score = remaining["score"].max() print(f"Step {n}: {best_idx} matched {len(remaining['matches'][best_idx]):d} parts (score: {best_score})") for cmp in remaining["matches"][best_idx]: if cmp in remaining.index: actual.loc[cmp] = nominal.loc[best_idx] # remove matched parts remaining.drop(remaining["matches"][best_idx], inplace=True) for idx in remaining.index: remaining["matches"].loc[idx] = set(remaining["matches"][idx]).intersection(remaining.index) n += 1