Skip to content

Commit

Permalink
Contest.similar(name)
Browse files Browse the repository at this point in the history
  • Loading branch information
JG1VPP committed Jul 14, 2024
1 parent 28cd5a5 commit 8c534ce
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/main/java/qxsl/ruler/Contest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import java.util.*;

import qxsl.utils.LevenDist;

/**
* コンテストの規約はこのクラスを継承します。
*
Expand Down Expand Up @@ -97,6 +99,22 @@ public final Section section(String name) {
return this.map.get(name);
}

/**
* 指定された名前に似た部門を検索します。
*
*
* @param name 部門の名前
*
* @return 類似する部門
*
* @since 2024/07/14
*/
public final Section similar(String name) {
final var shtein = LevenDist.comparator(name);
final var stream = this.map.keySet().stream();
return this.map.get(stream.min(shtein).get());
}

/**
* この規約の部門の名前のリストを返します。
*
Expand Down
66 changes: 66 additions & 0 deletions src/main/java/qxsl/utils/LevenDist.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*******************************************************************************
* Amateur Radio Operational Logging Library 'qxsl' since 2013 February 16th
* Released under the GNU Lesser General Public License (LGPL) v3 (see LICENSE)
* Univ. Tokyo Amateur Radio Club Development Task Force (https://nextzlog.dev)
*******************************************************************************/
package qxsl.utils;

import java.util.Comparator;
import java.util.function.ToIntBiFunction;

/**
* レーベンシュタイン距離の実装です。
*
*
* @author 無線部開発班
*
* @since 2024/07/14
*/
public final class LevenDist implements ToIntBiFunction<String, String> {
/**
* 指定された文字列と文字列の間の編集距離を計算します。
*
*
* @param str1 文字列
* @param str2 文字列
*
* @return 編集距離
*/
@Override
public final int applyAsInt(String str1, String str2) {
final int rows = str1.length() + 1;
final int cols = str2.length() + 1;
final var edit = new int[rows][cols];
for(int row = 0; row < rows; row++) edit[row][0] = row;
for(int col = 0; col < cols; col++) edit[0][col] = col;
for(int row = 1; row < rows; row++) {
for(int col = 1; col < cols; col++) {
final char c1 = str1.charAt(row - 1);
final char c2 = str2.charAt(col - 1);
final int pre = edit[row - 1][col - 1];
final int add = edit[row][col - 1] + 1;
final int del = edit[row - 1][col] + 1;
final int rep = c1 == c2? pre: pre + 1;
edit[row][col] = Math.min(rep, Math.min(add, del));
}
}
return edit[rows - 1][cols - 1];
}

/**
* 指定された文字列との距離で文字列の順序を定義します。
*
*
* @param anchor 文字列
*
* @return 順序の定義
*/
public static final Comparator<String> comparator(String anchor) {
final var leven = new LevenDist();
return (str1, str2) -> {
final int d1 = leven.applyAsInt(anchor, str1);
final int d2 = leven.applyAsInt(anchor, str2);
return Integer.compare(d1, d2);
};
}
}
30 changes: 30 additions & 0 deletions src/test/java/qxsl/utils/LevenDistTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* Amateur Radio Operational Logging Library 'qxsl' since 2013 February 16th
* Released under the GNU Lesser General Public License (LGPL) v3 (see LICENSE)
* Univ. Tokyo Amateur Radio Club Development Task Force (https://nextzlog.dev)
*******************************************************************************/
package qxsl.utils;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

/**
* {@link LevenDist}クラスの挙動を検査します。
*
*
* @author 無線部開発班
*
* @since 2024/07/14
*/
public final class LevenDistTest extends Assertions {
private final int apply(String str1, String str2) {
return new LevenDist().applyAsInt(str1, str2);
}

@Test
public void testApplyAsInt() {
assertThat(apply("364", "364")).isEqualTo(0);
assertThat(apply("114", "514")).isEqualTo(1);
assertThat(apply("889", "464")).isEqualTo(3);
}
}

0 comments on commit 8c534ce

Please sign in to comment.