2016-09-18 8 views
0

アルファベット順にソートされたarraylistを5セットに分割する必要があります。Javaを使用 - AとEの間 - FとJの間の単語のリストを含むセット2 - KとOの間の単語のリストを含むセット3 - UとUの間の単語のリストを含むセット5とZは、(AからEへ、FからJへ、AからEへ、FからJへ...)

私はそれを行う効率的な方法を教えてもらえますか?私は8

おかげで、 Tushar

+1

パイプラインは1つのコレクションにしか収集できません。マップ>に保存しないでください。 –

+1

すべての単語が大文字であると想定できますか? – Kelvin

答えて

2

あなたはすべての要素が最もパフォーマンス効率的方法はbinarySearch()subList()を使用するときに、簡単な大文字(すなわち、A-Z)で開始するを保証されてソートされたリストで始まる場合。

パフォーマンスは、binarySearch()からO(log n)です。

List<String> list = Arrays.asList("Actually", "Chalk", "Dramatic", "Fence", "Horrible", "Labored", 
            "Resonant", "Six", "Slap", "Spark", "Tin", "Treatment"); 
int idxF = Collections.binarySearch(list, "F"); 
int idxK = Collections.binarySearch(list, "K"); 
int idxP = Collections.binarySearch(list, "P"); 
int idxU = Collections.binarySearch(list, "U"); 
if (idxF < 0) idxF = ~idxF; 
if (idxK < 0) idxK = ~idxK; 
if (idxP < 0) idxP = ~idxP; 
if (idxU < 0) idxU = ~idxU; 
List<String> listA_E = list.subList(0, idxF); 
List<String> listF_J = list.subList(idxF, idxK); 
List<String> listK_O = list.subList(idxK, idxP); 
List<String> listP_T = list.subList(idxP, idxU); 
List<String> listU_Z = list.subList(idxU, list.size()); 
System.out.println(listA_E); 
System.out.println(listF_J); 
System.out.println(listK_O); 
System.out.println(listP_T); 
System.out.println(listU_Z); 

出力

[Actually, Chalk, Dramatic] 
[Fence, Horrible] 
[Labored] 
[Resonant, Six, Slap, Spark, Tin, Treatment] 
[] 

あなたがソートされていないリストで起動した場合、これを行うための最も効率的な方法は、Groupがグループを代表するユニークな値であるMap<Group, List<String>>を作成することです。グループの最初の文字(AFKPU)の単純なCharacterでもかまわない。 enum

パフォーマンスは、TreeMap/TreeSet建物からのO(n log n)です。

enum LetterGroup { 
    A_E, F_J, K_O, P_T, U_Z; 
    public static LetterGroup of(String s) { 
     char ch = Character.toUpperCase(s.charAt(0)); 
     if (ch >= 'A' && ch <= 'E') return A_E; 
     if (ch >= 'F' && ch <= 'J') return F_J; 
     if (ch >= 'K' && ch <= 'O') return K_O; 
     if (ch >= 'P' && ch <= 'T') return P_T; 
     if (ch >= 'U' && ch <= 'Z') return U_Z; 
     throw new IllegalArgumentException(s); 
    } 
} 

このような列挙型は、Java 8 Streamsを使用して実行できます。

List<String> list = Arrays.asList("dramatic","slap","chalk","fence","resonant","tin", 
            "six","labored","spark","treatment","horrible","actually"); 
Map<LetterGroup, Set<String>> groups = list.stream() 
              .collect(Collectors.groupingBy(LetterGroup::of, 
                      TreeMap::new, 
                      Collectors.toCollection(TreeSet::new))); 
for (Entry<LetterGroup, Set<String>> entry : groups.entrySet()) 
    System.out.println(entry); 

出力も非ソートされたリストのために働く

A_E=[actually, chalk, dramatic] 
F_J=[fence, horrible] 
K_O=[labored] 
P_T=[resonant, six, slap, spark, tin, treatment] 
+2

@(idxF <0)idxF =〜idxF; –

+1

@Joop Eggen:そのトリックは最初の一見で賢明に見えるかもしれませんが、読者は、関連する2の補数の性質の闘争を意識していないコレクションAPIのドキュメントでは '-index-1'を参照していることに注意してください。 '〜'演算子のためのバイトコード命令がないので、両方のバリアントが同じバイトコードを生成するという深い知識を加えてください... – Holger

+1

Btw、それを賢明にしたいのであれば、なぜ 'if(idxF <0)idxF^= - 1; '? – Holger

1

あなたは修飾子機能と列挙型などのいくつかの種類を必要とするJavaを使用しています(擬似コード):

enum Scope{AE, FJ, //... 

    static Scope inScope(String s){ 
     return Arrays.asStream(Scope.values()) 
      .stream().filter(s -> isInScope(s)).findFirst().get(); 
    } 
    abstract boolean isInScope(String word); 
} 

Function<String, Scope> f = Scope::inScope; 
// in code 
listOfWords.stream().groupBy(f).values(); 

Scope列挙は文字でグループを定義します。メソッドisInScopeでは、範囲内の単語が指定されているかどうかをチェックします。機能fは単なるショートカットです。最後の行は、単語をスコープでグループ化し、Map<Scope, List<String>>と値を抽出する操作です。

一般的な考え方は、標準APIにgroupByコレクタがあることです。それらは分類器機能を必要とする。その関数は、私の例のように、if、またはenumの束である可能性があります。

1

最も簡単な解決策はある

Map<Integer, List<String>> m = list.stream() 
    .collect(Collectors.groupingBy(s->Math.min((s.charAt(0)-'A'&~32)/5,4))); 

// the keys range from 0 to 4, as can be shown with: 
System.out.println("a-e: "+m.getOrDefault(0, Collections.emptyList())); 
System.out.println("f-j: "+m.getOrDefault(1, Collections.emptyList())); 
System.out.println("k-o: "+m.getOrDefault(2, Collections.emptyList())); 
System.out.println("p-t: "+m.getOrDefault(3, Collections.emptyList())); 
System.out.println("u-z: "+m.getOrDefault(4, Collections.emptyList())); 

あなたは5つのコレクションを運ぶのではなく、マップを使用することを検討している場合later-あなたはきれいなプリントキーを代わりに使うことができます:

String[] key={"a-e", "f-j", "k-o", "p-t", "u-z" }; 
Map<String, List<String>> m = list.stream() 
    .collect(Collectors.groupingBy(s->key[Math.min((s.charAt(0)-'A'&~32)/5,4)])); 

for(String k:key) System.out.println(k+": "+m.getOrDefault(k, Collections.emptyList())); 

もちろん、このコードはソートされたリストでも機能しますが、ソートされた性質は利用されません。効率のためにソートされた性質を利用するには、Andreas’ answerに示すように、バイナリ検索または同様の手法を使用する必要があります。もちろん、それは単一のgroupingBy操作よりもコードの方が少し複雑です...

関連する問題