가있는 경우 NSMutableArray
요소를 무작위로 임의 섞는 방법은 무엇입니까?
(아래에 게시 된 이것에 대한 내 대답이 있지만 Cocoa를 처음 사용하고 더 좋은 방법이 있는지 알고 싶습니다.)
업데이트 : @Mukesh가 지적한 것처럼 iOS 10 이상 및 macOS 10.12 이상에서는 -[NSMutableArray shuffledArray]
셔플하는 데 사용할 수 있는 방법이 있습니다. 자세한 내용은 https://developer.apple.com/documentation/foundation/nsarray/1640855-shuffledarray?language=objc 를 참조하십시오. (그러나 이것은 요소를 제자리에 섞지 않고 새로운 배열을 만듭니다.)
답변
swapObjectAtIndex 메소드가 필요하지 않습니다. exchangeObjectAtIndex : withObjectAtIndex :가 이미 존재합니다.
답변
NSMutableArray에 범주를 추가하여이 문제를 해결했습니다.
편집 : Ladd의 답변 덕분에 불필요한 방법이 제거되었습니다.
편집 : Gregory Goltsov의 답변과 miho 및 blahdiblah의 의견 덕분에 변경 (arc4random() % nElements)
되었습니다 .arc4random_uniform(nElements)
편집 : Ron의 의견 덕분에 루프 개선
편집 : Mahesh Agrawal의 의견 덕분에 배열이 비어 있지 않은지 확인했습니다.
// NSMutableArray_Shuffling.h
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#else
#include <Cocoa/Cocoa.h>
#endif
// This category enhances NSMutableArray by providing
// methods to randomly shuffle the elements.
@interface NSMutableArray (Shuffling)
- (void)shuffle;
@end
// NSMutableArray_Shuffling.m
#import "NSMutableArray_Shuffling.h"
@implementation NSMutableArray (Shuffling)
- (void)shuffle
{
NSUInteger count = [self count];
if (count <= 1) return;
for (NSUInteger i = 0; i < count - 1; ++i) {
NSInteger remainingCount = count - i;
NSInteger exchangeIndex = i + arc4random_uniform((u_int32_t )remainingCount);
[self exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex];
}
}
@end
답변
아직 댓글을 달 수 없기 때문에 전체 답변을 제공 할 것이라고 생각했습니다. 필자는 프로젝트에 대한 Kristopher Johnson의 구현을 다양한 방법으로 (실제로 간결하게 만들려고 노력했습니다) 수정했습니다. 그 중 하나 arc4random_uniform()
는 모듈로 편향을 피하기 때문 입니다.
// NSMutableArray+Shuffling.h
#import <Foundation/Foundation.h>
/** This category enhances NSMutableArray by providing methods to randomly
* shuffle the elements using the Fisher-Yates algorithm.
*/
@interface NSMutableArray (Shuffling)
- (void)shuffle;
@end
// NSMutableArray+Shuffling.m
#import "NSMutableArray+Shuffling.h"
@implementation NSMutableArray (Shuffling)
- (void)shuffle
{
NSUInteger count = [self count];
for (uint i = 0; i < count - 1; ++i)
{
// Select a random element between i and end of array to swap with.
int nElements = count - i;
int n = arc4random_uniform(nElements) + i;
[self exchangeObjectAtIndex:i withObjectAtIndex:n];
}
}
@end
답변
당신이 가져 오는 경우 GameplayKit
하는이 shuffled
API :
https://developer.apple.com/reference/foundation/nsarray/1640855-shuffled
let shuffledArray = array.shuffled()
답변
약간 개선되고 간결한 솔루션 (상위 답변과 비교).
알고리즘은 동일하며 문헌에서 ” Fisher-Yates shuffle ” 로 설명되어 있습니다.
Objective-C에서 :
@implementation NSMutableArray (Shuffle)
// Fisher-Yates shuffle
- (void)shuffle
{
for (NSUInteger i = self.count; i > 1; i--)
[self exchangeObjectAtIndex:i - 1 withObjectAtIndex:arc4random_uniform((u_int32_t)i)];
}
@end
스위프트 3.2 및 4.x에서 :
extension Array {
/// Fisher-Yates shuffle
mutating func shuffle() {
for i in stride(from: count - 1, to: 0, by: -1) {
swapAt(i, Int(arc4random_uniform(UInt32(i + 1))))
}
}
}
Swift 3.0 및 3.1에서 :
extension Array {
/// Fisher-Yates shuffle
mutating func shuffle() {
for i in stride(from: count - 1, to: 0, by: -1) {
let j = Int(arc4random_uniform(UInt32(i + 1)))
(self[i], self[j]) = (self[j], self[i])
}
}
}
답변
이것은 NSArrays 또는 NSMutableArrays를 섞는 가장 간단하고 빠른 방법입니다 (객체 퍼즐은 NSMutableArray이며 퍼즐 객체를 포함합니다. 배열의 초기 위치를 나타내는 퍼즐 객체 변수 색인에 추가했습니다)
int randomSort(id obj1, id obj2, void *context ) {
// returns random number -1 0 1
return (random()%3 - 1);
}
- (void)shuffle {
// call custom sort function
[puzzles sortUsingFunction:randomSort context:nil];
// show in log how is our array sorted
int i = 0;
for (Puzzle * puzzle in puzzles) {
NSLog(@" #%d has index %d", i, puzzle.index);
i++;
}
}
로그 출력 :
#0 has index #6
#1 has index #3
#2 has index #9
#3 has index #15
#4 has index #8
#5 has index #0
#6 has index #1
#7 has index #4
#8 has index #7
#9 has index #12
#10 has index #14
#11 has index #16
#12 has index #17
#13 has index #10
#14 has index #11
#15 has index #13
#16 has index #5
#17 has index #2
obj1과 obj2를 비교하고 가능한 값을 반환 할 항목을 결정할 수 있습니다.
- NSOrderedAscending = -1
- NSOrderedSame = 0
- NSOrderedDescending = 1
답변
GitHub의 SSToolKit 이라는 부분 으로이 방법을 사용하는 인기있는 라이브러리 가 있습니다 . 파일 NSMutableArray + SSToolkitAdditions.h는 셔플 방법을 포함합니다. 사용할 수도 있습니다. 이 중에서도 유용한 것들이 많이있는 것 같습니다.
이 라이브러리의 메인 페이지는 여기에 있습니다 .
이것을 사용하면 코드는 다음과 같습니다.
#import <SSCategories.h>
NSMutableArray *tableData = [NSMutableArray arrayWithArray:[temp shuffledArray]];
이 라이브러리에는 포드도 있습니다 (CocoaPods 참조).