web-dev-qa-db-ja.com

Java)でアルファベット順を生成する

アルファベットのシーケンスを生成する方法を探しています:

A, B, C, ..., Z, AA, AB, AC, ..., ZZ.

誰かがこれを行う便利な方法を提案できますか?どのようなデータ構造を利用できますか?

シーケンス内の次のコードを取得してからシーケンスをリセットするメソッドが欲しいのですが。

21
mip

私のバージョンはIteratorを実装し、intカウンターを維持しています。カウンタ値は、対応する文字列に変換されます。

import com.google.common.collect.AbstractIterator;

class Sequence extends AbstractIterator<String> {
    private int now;
    private static char[] vs;
    static {
        vs = new char['Z' - 'A' + 1];
        for(char i='A'; i<='Z';i++) vs[i - 'A'] = i;
    }

    private StringBuilder alpha(int i){
        assert i > 0;
        char r = vs[--i % vs.length];
        int n = i / vs.length;
        return n == 0 ? new StringBuilder().append(r) : alpha(n).append(r);
    }

    @Override protected String computeNext() {
        return alpha(++now).toString();
    }
}

イテレータでnext()を呼び出して使用します。

Sequence sequence = new Sequence();
for(int i=0;i<100;i++){
  System.out.print(sequence.next() + " ");
}

A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE

より大きなシーケンスのパフォーマンスが向上した実装では、共通のプレフィックスが再利用されます。

class SequencePrefix extends AbstractIterator<String> {
    private int now = -1;
    private String prefix = "";
    private static char[] vs;
    static {
        vs = new char['Z' - 'A' + 1];
        for(char i='A'; i<='Z';i++) vs[i - 'A'] = i;
    }

    private String fixPrefix(String prefix){
        if(prefix.length() == 0) return Character.toString(vs[0]);
        int last = prefix.length() - 1;
        char next = (char) (prefix.charAt(last) + 1);
        String sprefix = prefix.substring(0, last);
        return next - vs[0] == vs.length ? 
            fixPrefix(sprefix) + vs[0] : sprefix + next;
    }

    @Override protected String computeNext() {
        if(++now == vs.length) prefix = fixPrefix(prefix);
        now %= vs.length;
        return new StringBuilder().append(prefix).append(vs[now]).toString();
    }
}

この基本的なアルゴリズムを配列で機能する実装で書き直すと、パフォーマンスがさらに向上します。 (String.charAt、String.substring、およびStringBufferにはオーバーヘッドがあります。)

7
Thomas Jung

Wikipediaの Hexavigesimal#Bijective base-26Bijective numeration#全単射基数のプロパティ-k数字 を組み合わせて次のようにしました。

import static Java.lang.Math.*;

private static String getString(int n) {
    char[] buf = new char[(int) floor(log(25 * (n + 1)) / log(26))];
    for (int i = buf.length - 1; i >= 0; i--) {
        n--;
        buf[i] = (char) ('A' + n % 26);
        n /= 26;
    }
    return new String(buf);
}

Wolfram Alpha の助けを借りて。たぶん、最初のリンクで実装を使用する方が簡単だったでしょう。

28
user988346

整数から文字列を生成する1行の再帰関数:

static String str(int i) {
    return i < 0 ? "" : str((i / 26) - 1) + (char)(65 + i % 26);
}

使用例:

public static void main(String[] args) {
    for (int i = 0; i < 27*27; ++i) {
        System.out.println(i + " -> " + str(i));
    }
}

出力:

0 -> A
1 -> B
2 -> C
[...]
24 -> Y
25 -> Z
26 -> AA
27 -> AB
[...]
700 -> ZY
701 -> ZZ
702 -> AAA
703 -> AAB
[...]
727 -> AAZ
728 -> ABA
22
jon-hanson
public class SeqGen {
    public static void main(String[] args) {
        //This is the configurable param
        int seqWidth = 3;

        Double charSetSize = 26d;

        // The size of the array will be 26 ^ seqWidth. ie: if 2 chars wide, 26
        // * 26. 3 chars, 26 * 26 * 26
        Double total = Math.pow(charSetSize, (new Integer(seqWidth)).doubleValue());

        StringBuilder[] sbArr = new StringBuilder[total.intValue()];
        // Initializing the Array
        for(int j = 0; j <total; j++){
            sbArr[j] = new StringBuilder();
        }

        char ch = 'A';
        // Iterating over the entire length for the 'char width' number of times.
        // TODO: Can these iterations be reduced?
        for(int k = seqWidth; k >0; k--){
            // Iterating and adding each char to the entire array.        
            for(int l = 1; l <=total; l++){
                sbArr[l-1].append(ch);
                if((l % (Math.pow(charSetSize, k-1d))) == 0){
                    ch++;
                    if(ch > 'Z'){
                        ch = 'A';
                    }
                }
            }
        }

        //Use the stringbuilder array.
        for (StringBuilder builder : sbArr) {
            System.out.println(builder.toString());
        }
    }
}

example を参照し、要件に従って変更してください。

4
Hemant Metalia

以下に、反復的で再帰的なソリューションを作成しました。これらのソリューションに続いて、イテレーターを使用してシーケンス内のn個のアイテムを生成する方法を示す例があります。また、再帰的なソリューションを使ってコードゴルフを楽しみました。

ソリューション

反復

public static String indexToColumnItr(int index, char[] alphabet) {
    if (index <= 0)
        throw new IndexOutOfBoundsException("index must be a positive number");
    if (index <= alphabet.length)
        return Character.toString(alphabet[index - 1]);
    StringBuffer sb = new StringBuffer();
    while (index > 0) {
        sb.insert(0, alphabet[--index % alphabet.length]);
        index /= alphabet.length;
    }
    return sb.toString();
}

再帰的

public static String indexToColumnRec(int index, char[] alphabet) {
    if (index <= 0)
        throw new IndexOutOfBoundsException("index must be a positive number");
    if (index <= alphabet.length)
        return Character.toString(alphabet[index - 1]);
    return indexToColumnRec(--index / alphabet.length, alphabet) + alphabet[index % alphabet.length];
}

使用法

public static final char[] ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();

indexToColumnItr(703, ALPHABET); // AAA

以下のコードは、サイズ52の次のシーケンスを生成しました。

[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW, AX, AY, AZ]

Main.Java

import Java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        System.out.println(Arrays.toString(AlphaUtils.generateSequence(52)));
    }
}

AlphaIterator.Java

import Java.util.Iterator;

public class AlphaIterator implements Iterator<String> {
    private int maxIndex;
    private int index;
    private char[] alphabet;

    public AlphaIterator() {
        this(Integer.MAX_VALUE);
    }

    public AlphaIterator(int maxIndex) {
        this(maxIndex, "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray());
    }

    public AlphaIterator(char[] alphabet) {
        this(Integer.MAX_VALUE, alphabet);
    }

    public AlphaIterator(int maxIndex, char[] alphabet) {
        this.maxIndex = maxIndex;
        this.alphabet = alphabet;
        this.index = 1;
    }

    @Override
    public boolean hasNext() {
        return this.index < this.maxIndex;
    }

    @Override
    public String next() {
        return AlphaUtils.indexToColumnItr(this.index++, this.alphabet);
    }
}

AlphaUtils.Java

public class AlphaUtils {
    // Iterative
    public static String indexToColumnItr(int index, char[] alphabet) {
        if (index <= 0) throw new IndexOutOfBoundsException("index must be a positive number");
        if (index <= alphabet.length) return Character.toString(alphabet[index - 1]);
        StringBuffer sb = new StringBuffer();
        while (index > 0) {
            sb.insert(0, alphabet[--index % alphabet.length]);
            index /= alphabet.length;
        }
        return sb.toString();
    }

    // Recursive
    public static String indexToColumnRec(int index, char[] alphabet) {
        if (index <= 0) throw new IndexOutOfBoundsException("index must be a positive number");
        if (index <= alphabet.length) return Character.toString(alphabet[index - 1]);
        return indexToColumnRec(--index / alphabet.length, alphabet) + alphabet[index % alphabet.length];
    }

    public static String[] generateSequence(int size) {
        String[] sequence = new String[size];
        int i = 0;
        for (AlphaIterator it = new AlphaIterator(size); it.hasNext();) {
            sequence[i++] = it.next();
        }
        return sequence;
    }
}

コードゴルフ(89バイト):-)

String f(int i,char[]a){int l=a.length;return i<=0?"?":i<=l?""+a[i-1]:f(--i/l,a)+a[i%l];}
3
Mr. Polywhirl

このメソッドは、アルファベット文字シーケンスを生成します

Nullで呼び出された場合はAを返します。Aで呼び出された場合はBを返します。

シーケンスはA、B、C ...... Z、AA、AB、AC ..... AZ、BA、BB、BC .... BZ、CA、CB、CC .... CZのようになります、DA ...... ZA、ZB .... ZZ、AAA、AAB、AAC .... AAZ、ABA、ABB ... AZZ、BAA、BAB .... ZZZ

/**
* @param charSeqStr
* @return
*/

public static String getNextAlphaCharSequence(String charSeqStr) {

    String nextCharSeqStr       = null;
    char[] charSeqArr           = null;
    boolean isResetAllChar      = false;
    boolean isResetAfterIndex   = false;
    Integer resetAfterIndex     = 0;

    if (StringUtils.isBlank(charSeqStr)) {
        charSeqArr = new char[] { 'A' };
    } else {
        charSeqArr = charSeqStr.toCharArray();
        Integer charSeqLen = charSeqArr.length;

        for (int index = charSeqLen - 1; index >= 0; index--) {
            char charAtIndex = charSeqArr[index];

            if (Character.getNumericValue(charAtIndex) % 35 == 0) {
                if (index == 0) {
                    charSeqArr = Arrays.copyOf(charSeqArr, charSeqLen + 1);
                    isResetAllChar = true;
                } else {
                    continue;
                }
            } else {
                char nextCharAtIndex = (char) (charAtIndex + 1);
                charSeqArr[index] = nextCharAtIndex;
                if (index + 1 < charSeqLen) {
                    isResetAfterIndex = true;
                    resetAfterIndex = index;
                }
                break;
            }
        }
        charSeqLen = charSeqArr.length;
        if (isResetAllChar) {
            for (int index = 0; index < charSeqLen; index++) {
                charSeqArr[index] = 'A';
            }
        } else if (isResetAfterIndex) {
            for (int index = resetAfterIndex + 1; index < charSeqLen; index++) {
                charSeqArr[index] = 'A';
            }
        }
    }

    nextCharSeqStr = String.valueOf(charSeqArr);
    return nextCharSeqStr;
}

public static void main(String args[]) {
    String nextAlphaSequence = null;
    for (int index = 0; index < 1000; index++) {
        nextAlphaSequence = getNextAlphaCharSequence(nextAlphaSequence);
        System.out.print(nextAlphaSequence + ",");
    }
}
2
Murali

私はテストしていましたが、コードが悪いです...

256まで動作というコードを作成しましたが、必要に応じて変更できます。

  public static String IntToLetter(int Int) {
    if (Int<27){
      return Character.toString((char)(Int+96));
    } else {
      if (Int%26==0) {
        return IntToLetter((Int/26)-1)+IntToLetter((Int%26)+1);
      } else {
        return IntToLetter(Int/26)+IntToLetter(Int%26);
      }
    }
  }

編集済み(メソッド修正済み):

  public static String IntToLetter(int Int) {
    if (Int<27){
      return Character.toString((char)(Int+96));
    } else {
      if (Int%26==0) {
        return IntToLetter((Int/26)-1)+IntToLetter(((Int-1)%26+1));
      } else {
        return IntToLetter(Int/26)+IntToLetter(Int%26);
      }
    }
  }

コードのテスト:

  for (int i = 1;i<256;i++) {
    System.out.println("i="+i+" -> "+IntToLetter(i));
  }

結果

    i=1 -> a
    i=2 -> b
    i=3 -> c
    i=4 -> d
    i=5 -> e
    i=6 -> f
    i=7 -> g
    i=8 -> h
    i=9 -> i
    i=10 -> j
    i=11 -> k
    i=12 -> l
    i=13 -> m
    i=14 -> n
    i=15 -> o
    i=16 -> p
    i=17 -> q
    i=18 -> r
    i=19 -> s
    i=20 -> t
    i=21 -> u
    i=22 -> v
    i=23 -> w
    i=24 -> x
    i=25 -> y
    i=26 -> z
    i=27 -> aa
    i=28 -> ab
    i=29 -> ac
    i=30 -> ad
    i=31 -> ae
    i=32 -> af
    i=33 -> ag
    i=34 -> ah
    i=35 -> ai
    i=36 -> aj
    i=37 -> ak
    i=38 -> al
    i=39 -> am
    i=40 -> an
    i=41 -> ao
    i=42 -> ap
    i=43 -> aq
    i=44 -> ar
    i=45 -> as
    i=46 -> at
    i=47 -> au
    i=48 -> av
    i=49 -> aw
    i=50 -> ax
    i=51 -> ay
    i=52 -> az
    i=53 -> ba
    i=54 -> bb
    i=55 -> bc
    i=56 -> bd
    i=57 -> be
    i=58 -> bf
    i=59 -> bg
    i=60 -> bh
    i=61 -> bi
    i=62 -> bj
    i=63 -> bk
    i=64 -> bl
    i=65 -> bm
    i=66 -> bn
    i=67 -> bo
    i=68 -> bp
    i=69 -> bq
    i=70 -> br
    i=71 -> bs
    i=72 -> bt
    i=73 -> bu
    i=74 -> bv
    i=75 -> bw
    i=76 -> bx
    i=77 -> by
    i=78 -> bz
    i=79 -> ca
    i=80 -> cb
    i=81 -> cc
    i=82 -> cd
    i=83 -> ce
    i=84 -> cf
    i=85 -> cg
    i=86 -> ch
    i=87 -> ci
    i=88 -> cj
    i=89 -> ck
    i=90 -> cl
    i=91 -> cm
    i=92 -> cn
    i=93 -> co
    i=94 -> cp
    i=95 -> cq
    i=96 -> cr
    i=97 -> cs
    i=98 -> ct
    i=99 -> cu
    i=100 -> cv
    i=101 -> cw
    i=102 -> cx
    i=103 -> cy
    i=104 -> cz
    i=105 -> da
    i=106 -> db
    i=107 -> dc
    i=108 -> dd
    i=109 -> de
    i=110 -> df
    i=111 -> dg
    i=112 -> dh
    i=113 -> di
    i=114 -> dj
    i=115 -> dk
    i=116 -> dl
    i=117 -> dm
    i=118 -> dn
    i=119 -> do
    i=120 -> dp
    i=121 -> dq
    i=122 -> dr
    i=123 -> ds
    i=124 -> dt
    i=125 -> du
    i=126 -> dv
    i=127 -> dw
    i=128 -> dx
    i=129 -> dy
    i=130 -> dz
    i=131 -> ea
    i=132 -> eb
    i=133 -> ec
    i=134 -> ed
    i=135 -> ee
    i=136 -> ef
    i=137 -> eg
    i=138 -> eh
    i=139 -> ei
    i=140 -> ej
    i=141 -> ek
    i=142 -> el
    i=143 -> em
    i=144 -> en
    i=145 -> eo
    i=146 -> ep
    i=147 -> eq
    i=148 -> er
    i=149 -> es
    i=150 -> et
    i=151 -> eu
    i=152 -> ev
    i=153 -> ew
    i=154 -> ex
    i=155 -> ey
    i=156 -> ez
    i=157 -> fa
    i=158 -> fb
    i=159 -> fc
    i=160 -> fd
    i=161 -> fe
    i=162 -> ff
    i=163 -> fg
    i=164 -> fh
    i=165 -> fi
    i=166 -> fj
    i=167 -> fk
    i=168 -> fl
    i=169 -> fm
    i=170 -> fn
    i=171 -> fo
    i=172 -> fp
    i=173 -> fq
    i=174 -> fr
    i=175 -> fs
    i=176 -> ft
    i=177 -> fu
    i=178 -> fv
    i=179 -> fw
    i=180 -> fx
    i=181 -> fy
    i=182 -> fz
    i=183 -> ga
    i=184 -> gb
    i=185 -> gc
    i=186 -> Gd
    i=187 -> ge
    i=188 -> gf
    i=189 -> gg
    i=190 -> gh
    i=191 -> gi
    i=192 -> gj
    i=193 -> gk
    i=194 -> gl
    i=195 -> gm
    i=196 -> gn
    i=197 -> go
    i=198 -> gp
    i=199 -> gq
    i=200 -> gr
    i=201 -> gs
    i=202 -> gt
    i=203 -> gu
    i=204 -> gv
    i=205 -> gw
    i=206 -> gx
    i=207 -> gy
    i=208 -> gz
    i=209 -> ha
    i=210 -> hb
    i=211 -> hc
    i=212 -> hd
    i=213 -> he
    i=214 -> hf
    i=215 -> hg
    i=216 -> hh
    i=217 -> hi
    i=218 -> hj
    i=219 -> hk
    i=220 -> hl
    i=221 -> hm
    i=222 -> hn
    i=223 -> ho
    i=224 -> hp
    i=225 -> hq
    i=226 -> hr
    i=227 -> hs
    i=228 -> ht
    i=229 -> hu
    i=230 -> hv
    i=231 -> hw
    i=232 -> hx
    i=233 -> hy
    i=234 -> hz
    i=235 -> ia
    i=236 -> ib
    i=237 -> ic
    i=238 -> id
    i=239 -> ie
    i=240 -> if
    i=241 -> ig
    i=242 -> ih
    i=243 -> ii
    i=244 -> ij
    i=245 -> ik
    i=246 -> il
    i=247 -> im
    i=248 -> in
    i=249 -> io
    i=250 -> ip
    i=251 -> iq
    i=252 -> ir
    i=253 -> is
    i=254 -> it
    i=255 -> iu

宜しくお願いします

2
chepe lucho

興味深いことに、まだ誰もJava 8ベースの関数ソリューションを提供していません。これは jOOλ を使用したソリューションで、文字にrange()のような機能を提供します。 、foldLeft()およびcrossJoin()(免責事項、私はjOOλを維持している会社で働いています):

int max = 3;

List<String> alphabet = Seq
    .rangeClosed('A', 'Z')
    .map(Object::toString)
    .toList();

Seq.rangeClosed(1, max)
   .flatMap(length ->
       Seq.rangeClosed(1, length - 1)
          .foldLeft(Seq.seq(alphabet), (s, i) -> s.crossJoin(Seq.seq(alphabet))
                                                  .map(t -> t.v1 + t.v2)))
   .forEach(System.out::println);

このソリューションはそれほど高速ではありません( たとえば、このソリューションのように )。完全を期すために追加しました。

1
Lukas Eder
    char ch;
    String str1 = "";
    String str2 = "";

    for (ch = 'A'; ch <= 'Z'; ch++) {
        str1 += ch;
        for (int i = 0; i < 26; i++) {
            char upper = (char) ('A' + i);
            str2 = str2 + ch + upper + " ";

        }
    }

    System.out.println(str1 + ", " + str2);
1
GIRI

次の値を返すイテレータをお勧めします。

イテレータは、内部カウンタに基づいて、返す文字列を作成できる必要があります。あなたの例では、2つのカウンターで十分です。 1つは文字列の最初の文字用で、もう1つは2番目の文字用です。

各カウンターは、_" ABCDEFGHIJKLMNOPQRSTUVWXYZ"_のインデックスに対応できます。文字列を返したら、最後の位置のカウンターを更新します。 「エッジを超えて」落ちた場合は、「A」を指すようにリセットし、次のカウンターをインクリメントします。そのカウンターが大きくなったら、必要に応じて、イテレーターに要素がもうないことを示すか、「」を指すようにリセットします。

最初の位置を空白にすることで、文字列でtrim()を使用して、最初の応答に「A」を与えるスペースを取り除くことができることに注意してください。

これらすべての長い答え...そして再帰を使用するもの...すごい。これは、Javaで、再帰なしで数行で実行できます。

private static String intToValueKey(int value) {
    final StringBuilder sb = new StringBuilder(String.valueOf((char)('A'+(value % 26))));
    while((value = (value/26-1)) >= 0) {
        sb.append((char)('A'+(value % 26)));
    }
    return sb.reverse().toString();
}

次に、ループ内で数値を増やしながらメソッドを呼び出すだけで、0からnまでのシーケンスが生成されます。

for(int i=0; i<800; i++) {
    System.out.println(intToValueKey(i));
}

最後のreverse()は、文字の順序を気にする場合だけであり、一意の順列を探しているだけの場合は実際には必要ありません。

0
ApolloX

これにより、渡された値のシーケンスが作成されます。

/**
 * Method that returns batch names based on passed value
 * @param batchCount
 * @return String[]
 */
public static String[] getBatchNamesForExecutor(int batchCount) {
    // Batch names array
    String[] batchNames = new String[batchCount];

    // Loop from 0 to batchCount required
    for(int index=0; index < batchCount; index++) {
        // Alphabet for current batch name 
        int alphabet = index%26;

        // iteration count happened on all alphabets till now
        int iterations = index/26;

        // initializing array element to blank string
        batchNames[index] = "";

        // Looping over the iterationIndex and creating batch alphabet prefix / prefixes
        for(int iterationIndex = 0; iterationIndex < iterations; iterationIndex+=26){
            batchNames[index] += String.valueOf((char)('A' + (iterations-1) % 26 ));
        }

        // Adding last alphabet in batch name
        batchNames[index] += String.valueOf((char)('A' + alphabet % 26 ));
    }

    return batchNames;
}

public static void main(String[] args) {
    for(String s: getBatchNamesForExecutor(8))  {
        System.err.println(s);
    }
    System.exit(0); 
}
0
user3637856

私はJavaの関数型プログラミングに精通していませんが、Haskellでこのコードと同等のことを実行できると思います。

-リストを作成します["A" .. "Z"]

uca = map(:[])['A' .. 'Z']

-文字列の2つのリストのデカルト積、++は2つの文字列を連結します

cp lst1 lst2 =

    [x ++ y | x <- lst1, y <- lst2]

-以下に必要な文字列のリストを示します

uca ++ cp uca uca

0
George Co

「A」から「Z」を26radixとします。例(C++)

    vector<string> generateSequenceBySize(int N)
    {
        if(N<1)
            return vector<string>();
        int base = 26;
        vector<string> seqs;
        for(int i=0;i<pow(base,N);i++)
        {
            int value = i;
            string tmp(N,'A');
            for (int j=0;j<N;j++)
            {
                tmp[N-1-j] = 'A'+value%base;
                value = value/base;
            }
            seqs.Push_back(tmp);
        }
        return seqs;
    }
    vector<string> generateSequence()
    {
        //http://stackoverflow.com/questions/8710719/generating-an-alphabetic-sequence-in-Java
        //A, B, C, ..., Z, AA, AB, AC, ..., ZZ.
        vector<string> seqs;
        for (int i=1;i<=2;i++)
        {
            vector<string> subSeq = generateSequenceBySize(i);
            seqs.insert(seqs.end(),subSeq.begin(),subSeq.end());
        }
        return seqs;
    }
0
user5461120

ショートコードが好きだから… トーマス・ユングの答え

static String asLetters(long value) {
    int codePoint = (int) ('A' + --value % 26);
    long higher = value / 26;
    String letter = new String(Character.toChars(codePoint));
    return higher == 0 ? letter : asLetters(higher).concat(letter);
}

1→aから始まりLong.MAX_VALUECRPXNLSKVLJFHGまで。小文字には'a'の代わりに'A'を使用してください。

0
Matthias Ronge