2013-01-15 72 views
2

我想要隨機化字母表中所有字符的字符串。現在,我創建了26個字符的可變數組,使用exchangeObjectAtIndex:方法對它們進行混洗,然後將每個字符添加到我返回的字符串中。生成隨機字母串的有效方法?

必須有更好的方法來做到這一點。這裏是我的代碼:

- (NSString *)shuffledAlphabet { 
    NSMutableArray * shuffledAlphabet = [NSMutableArray arrayWithArray:@[@"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"]]; 

    for (NSUInteger i = 0; i < [shuffledAlphabet count]; ++i) { 
     // Select a random element between i and end of array to swap with. 
     int nElements = [shuffledAlphabet count] - i; 
     int n = (random() % nElements) + i; 
     [shuffledAlphabet exchangeObjectAtIndex:i withObjectAtIndex:n]; 
    } 

    NSString *string = [[NSString alloc] init]; 
    for (NSString *letter in shuffledAlphabet) { 
     string = [NSString stringWithFormat:@"%@%@",string,letter]; 
    } 

    return string; 
} 
+0

你想要一個隨機的字母串,還是要隨機排列字母表中的字母(即「沒有重複的隨機序列」)? - 你的問題的標題是第一個,而你的代碼是後者。 –

+0

我很高興重複字母或簡單的洗牌字母表。當我寫出這種方法時,首先想到的是洗牌字母表。 – Joshua

+1

來吧,決定你想要什麼。其中兩個真的不同。 – erkanyildiz

回答

7

下面是一個有效的Fisher-Yates shuffle,適應你的使用情況:

- (NSString *)shuffledAlphabet { 
    NSString *alphabet = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 

    // Get the characters into a C array for efficient shuffling 
    NSUInteger numberOfCharacters = [alphabet length]; 
    unichar *characters = calloc(numberOfCharacters, sizeof(unichar)); 
    [alphabet getCharacters:characters range:NSMakeRange(0, numberOfCharacters)]; 

    // Perform a Fisher-Yates shuffle 
    for (NSUInteger i = 0; i < numberOfCharacters; ++i) { 
     NSUInteger j = (arc4random_uniform(numberOfCharacters - i) + i); 
     unichar c = characters[i]; 
     characters[i] = characters[j]; 
     characters[j] = c; 
    } 

    // Turn the result back into a string 
    NSString *result = [NSString stringWithCharacters:characters length:numberOfCharacters]; 
    free(characters); 
    return result; 
} 
0

你可以挑選從(其餘的)字母隨機元素,當你建立你的字符串,而不是第一次洗牌它的:

NSMutableArray *alphabet = [NSMutableArray arrayWithObjects:@"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", nil]; 
NSMutableString *result = [NSMutableString string]; 
NSUInteger numberOfLetters = alphabet.count; 
for (NSUInteger i = 0; i < numberOfLetters; i++) { 
    int n = arc4random() % alphabet.count; 
    [result appendString:[alphabet objectAtIndex:n]]; 
    [alphabet removeObjectAtIndex:n]; 
} 
NSLog(@"%@", result); 

這使代碼更短一些。還請注意,使用NSMutableString比每次添加一封信時創建新的NSString更有效。

+1

使用排序算法來洗牌數組不是一個好主意。首先,不同的組合不具有相同的概率。其次,它的漸近複雜度爲O(log(n)* n),而高效的混洗算法的複雜度爲O(n)。你應該看看對[這個問題]的迴應(http://stackoverflow.com/questions/790083/does-qsort-demand-consistent-comparisons-or-can-i-use-it-for-shuffling) 。 –

+1

感謝您的鏈接。我已經刪除了替代版本。 – omz

2

這是執行正常洗牌字母代更有效的方式。

- (NSString *)shuffledAlphabet 
{ 
    const NSUInteger length = 'Z' - 'A' + 1; 
    unichar alphabet[length]; 
    alphabet[0] = 'A'; 

    for (NSUInteger i = 1; i < length; i++) 
    { 
     NSUInteger j = arc4random_uniform((uint32_t)i + 1); 
     alphabet[i] = alphabet[j]; 
     alphabet[j] = 'A' + i; 
    } 
    return [NSString stringWithCharacters:alphabet length:length]; 
} 

它使用費耶茨洗牌的「由內而外」的版本,並通過與arc4random_uniform產生僞隨機數可以避免MODULA偏差。此外,它需要一個單獨的分配,因爲所有的排列都在一個臨時緩衝區中執行。

+1

這個答案中應該有鏈接。我不明白他們爲什麼不顯示。 –