| 2519 | |
| 2520 | namespace edit_distance { |
| 2521 | std::vector<EditType> CalculateOptimalEdits(const std::vector<size_t>& left, |
| 2522 | const std::vector<size_t>& right) { |
| 2523 | std::vector<std::vector<double> > costs( |
| 2524 | left.size() + 1, std::vector<double>(right.size() + 1)); |
| 2525 | std::vector<std::vector<EditType> > best_move( |
| 2526 | left.size() + 1, std::vector<EditType>(right.size() + 1)); |
| 2527 | |
| 2528 | // Populate for empty right. |
| 2529 | for (size_t l_i = 0; l_i < costs.size(); ++l_i) { |
| 2530 | costs[l_i][0] = static_cast<double>(l_i); |
| 2531 | best_move[l_i][0] = kRemove; |
| 2532 | } |
| 2533 | // Populate for empty left. |
| 2534 | for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { |
| 2535 | costs[0][r_i] = static_cast<double>(r_i); |
| 2536 | best_move[0][r_i] = kAdd; |
| 2537 | } |
| 2538 | |
| 2539 | for (size_t l_i = 0; l_i < left.size(); ++l_i) { |
| 2540 | for (size_t r_i = 0; r_i < right.size(); ++r_i) { |
| 2541 | if (left[l_i] == right[r_i]) { |
| 2542 | // Found a match. Consume it. |
| 2543 | costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; |
| 2544 | best_move[l_i + 1][r_i + 1] = kMatch; |
| 2545 | continue; |
| 2546 | } |
| 2547 | |
| 2548 | const double add = costs[l_i + 1][r_i]; |
| 2549 | const double remove = costs[l_i][r_i + 1]; |
| 2550 | const double replace = costs[l_i][r_i]; |
| 2551 | if (add < remove && add < replace) { |
| 2552 | costs[l_i + 1][r_i + 1] = add + 1; |
| 2553 | best_move[l_i + 1][r_i + 1] = kAdd; |
| 2554 | } else if (remove < add && remove < replace) { |
| 2555 | costs[l_i + 1][r_i + 1] = remove + 1; |
| 2556 | best_move[l_i + 1][r_i + 1] = kRemove; |
| 2557 | } else { |
| 2558 | // We make replace a little more expensive than add/remove to lower |
| 2559 | // their priority. |
| 2560 | costs[l_i + 1][r_i + 1] = replace + 1.00001; |
| 2561 | best_move[l_i + 1][r_i + 1] = kReplace; |
| 2562 | } |
| 2563 | } |
| 2564 | } |
| 2565 | |
| 2566 | // Reconstruct the best path. We do it in reverse order. |
| 2567 | std::vector<EditType> best_path; |
| 2568 | for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { |
| 2569 | EditType move = best_move[l_i][r_i]; |
| 2570 | best_path.push_back(move); |
| 2571 | l_i -= move != kAdd; |
| 2572 | r_i -= move != kRemove; |
| 2573 | } |
| 2574 | std::reverse(best_path.begin(), best_path.end()); |
| 2575 | return best_path; |
| 2576 | } |
| 2577 | |
| 2578 | namespace { |
no test coverage detected