6

私は文字列のリストを持っています。double を返す関数に基づいて各文字列を評価したいと考えています。次に、計算された値に基づいて、最初の 5 つの文字列が必要です。5つに満たない場合は、すべて(順番に)欲しいです。文字列が化学化合物であり、関数が質量を計算するとしましょう。関数は計算コストが高くなります。文字列ごとに 1 回評価する必要があります。(ただし、ここではデータを作成しているだけです。)

H2O => 18.5
C12H11O22 => 109.1
HeNe => 32.0
H2SO4 => 54.37
HCl => 19.11
4FeO3 => 82.39
Xe6 => 281.9

プログラムは、それぞれの値の順に並べられた最初の 5 つの文字列を返す必要があります。このサンプル データの場合: H20, HCl, HeNe, H2SO4, 4FeO3. 実際、順番はあまり気にしません。必要なのは、任意の順序で最も低い 5 つだけです。

Perl でこれを行う方法を考えました。それはほんの数行です:

foreach $s (@str) {
    $strmap{$s} = f($s);
}
@sorted = sort { $strmap{$a} <=> $strmap{$b} } keys %strmap;
return @sorted[0, 4]

しかし、私はJavaでそれを行う必要があります。そして、それは私を夢中にさせています。

まず、Perl バージョンと同じように、カスタム コンパレータHashMap<String, Double>を使用して、 を設定してみました。Collections.sortしかし、Comparator のスコープにより、HashMap を参照して値を検索することができませんでした。

次に、を試しましたTreeMap<String, Double>が、キーでソートするだけで、強制的にエントリを値で並べ替えることができませんでした。

だから私は試してみましたTreeMap<Double, String>。同じ Double を持つエントリは破棄されます。ただし、同じ Double にマップされる String を持つ可能性は低いため、先に進みました。TreeMap にエントリを追加することは問題ありませんが、そこから値を抽出しようとすると問題が発生しました。

TreeMap は と呼ばれるメソッドを提供subMapしますが、そのパラメーターはサブセットを区切るキーです。それらが何であるかはわかりません。欲しいのは最初の5つだけです。そこで、このvaluesメソッドを使用して TreeMap からすべての値を取得しようとしました。その後、最初の 10 を取得できます。

ArrayList<String> strs = (ArrayList<String>)(treemap.values());
return new ArrayList<String>(strs.subList(0, 5));

いいえ。実行時エラー: TreeMap$Values を ArrayList にキャストできません。

List<String> strs = (List<String>)(treemap.values());
return new ArrayList<String>(strs.subList(0, 5));

同じ。キャストを実行しようとしたときにランタイム エラーが発生しました。OK、コレクションに割り当てましょう...

Collection<String> strs = treemap.values();
return new ArrayList<String>(strs.subList(0, 5));

申し訳ありませんが、subListコレクションの方法ではありません。

Collection<String> strs = treemap.values();
ArrayList<String> a = new ArrayList<String>(strs);
return new ArrayList<String>(a.subList(0,  5));

最後に、機能するもの!しかし、最初の 5 つの要素を取得するためだけに 2 つの追加のデータ構造が必要ですか? また、私は Double を TreeMap のキーとして使用することについて、それほど熱心ではありません。

より良い解決策はありますか?

4

3 に答える 3

3

Java ではなく、上記の 3 行よりもコンパクトになるとは思いません。

それとは別にMap、データ構造としての a はそもそも間違った選択であるという印象があります.そうは言っていない)。別のアプローチは、独自の同等のデータ レコード クラスを宣言することです。

private static class Record implements Comparable<Record> {
    // public final fields ok for this small example
    public final String string;
    public final double value;

    public Record(String string, double value) {
        this.string = string;
        this.value = value;
    }

    @Override
    public int compareTo(Record other) {
        // define sorting according to double fields
        return Double.compare(value, other.value); 
    }
}

// provide size to avoid reallocations
List<Record> records = new ArrayList<Record>(stringList.size());
for(String s : stringList)
    records.add(new Record(s, calculateFitness(s));
Collections.sort(records); // sort according to compareTo method
int max = Math.min(10, records.size()); // maximum index
List<String> result = new ArrayList<String>(max);
for(int i = 0; i < max; i++)
    result.add(records.get(i).string);
return result;

これは、上記の 3 行よりもはるかに冗長ですが (これは結局 Java です)、キーと値のペアをマップに挿入するために必要なコードも含まれています。

于 2013-04-30T09:59:19.377 に答える
1

次のようなものがあなたのために働きますか?

データを並べ替える以外に double 値は必要ないと仮定していることに注意してください。

public static void main(String[] args) throws Exception {
  List<String> data = new ArrayList<>(Arrays.asList("t", "h", "i", "s", "i", "s", "t", "e", "s", "t", "d", "a", "t", "a"));

  Collections.sort(data, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
      double o1Value = evaluate(o1);
      double o2Value = evaluate(o2);
      return Double.compare(o1Value, o2Value);
    }
  });

  List<String> result = data.subList(0, 10); // Note the end point is exclusive

  for (String s : result) {
    System.out.println(s);
  }
}

private static double evaluate(String s) {
  return s.codePointAt(0); // Nonsense, I know
}

この例では、次のように出力されます。

a
a
d
e
h
i
i
s
s
s
于 2013-04-30T09:57:38.347 に答える
0

StringDoubleおよび計算を行う関数を組み合わせたクラスを作成してみませんか?次のようなものです。

public Thing implements Comparable<Thing>
{
  private String s;
  private Double d;

  public Thing(String s)
  {
    this.s = s;
    this.d = calculateDouble(s); 
  }

  public String getString()
  {
    return this.s;
  }

  public Double getDouble()
  {
    return this.d;
  }

  public int compareTo(Thing other)
  {
    return getDouble().compareTo(other.getDouble());
  }

  public Double calculateDouble(String s)
  {
    ...
  }
}

次に、必要なのはList<Thing>Collections.sortおよびList.subListです。

于 2013-04-30T09:57:41.127 に答える