문제

이 있는 경우 NSMutableArray, 을,당신은 어떻게 셔플의 요소를 임의로?

(나는 내 자신의 답변에 대한 이는 아래에 게시 된,그러나 나는 새로운 코코아 및 나는 흥미를 알고 있는 경우에 더 좋은 방법입니다.)


업데이트:으로 주목 by@무 케시의로,iOS10+와 맥 os10.12+가 -[NSMutableArray shuffledArray] 할 수 있는 방법을 사용하는 셔플.보 https://developer.apple.com/documentation/foundation/nsarray/1640855-shuffledarray?language=objc 자세한 내용은.(하지만 참고 있는 이 새로운 배열보다는 셔플의 요소를 배치.)

도움이 되었습니까?

해결책

당신이 필요하지 않 swapObjectAtIndex 방법입니다. exchangeObjectAtIndex:withObjectAtIndex: 이미 존재합니다.

다른 팁

도 추가하여 이 범주를 NSMutableArray.

편집: 제 불필요한 방법 덕분에 응답에 의해 래드.

편집: 변경 (arc4random() % nElements) 하기 arc4random_uniform(nElements) 감사에 대답하여 그레고리 Goltsov 과 코멘트에 의해 미호 및 blahdiblah

편집: 루프 개선,덕분에 코멘트에 의해 Ron

편집: 추가 확인하는 배열이 비어 있지 않으면 감사하의 의견 Mahesh 왈

//  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 존슨의 구현은 내에서 프로젝트 방법의 수(수 있도록 노력합니다 그것은 가능한 한 간결한),그들 중 하나는 arc4random_uniform() 기 때문에 그것을 피 모듈 bias.

// 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

아이폰 os 에서 10 여 사용할 수 있는 새로운 shuffled API:

https://developer.apple.com/reference/foundation/nsarray/1640855-shuffled

let shuffledArray = array.shuffled()

약간 향상하고 간결한 솔루션을(상단에 비해 답변).

알고리즘 같은 문학으로 설명되"Fisher-Yates 섞".

하는 것을 목적으:

@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))))
        }
    }
}

스 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])
        }
    }
}

참고: 더 간결 솔루션 스위프트는에서 가능한 iOS10 사용 GameplayKit.

참고: 는 알고리즘에 대한 불안정한 셔플(모든 위치를 강요하는 경우 변경할 수>1)사용할 수 있도

이는 간단하고 빠른 방법을 섞 NSArrays 또는 NSMutableArrays (object 퍼즐 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

가 인기있는 라이브러리는 이 방법으로 그것의 일부라 SSToolKit 에 GitHub.파일 NSMutableArray+SSToolkitAdditions.서 포함되는 셔플 방법입니다.당신도 사용할 수 있습니다.이 중 보실 수 있습니다 톤의 유용한 것들입니다.

의 기본 페이지 이 라이브러리 .

당신이 사용하는 경우,당신의 코드는 다음과 같이 될 것이다:

#import <SSCategories.h>
NSMutableArray *tableData = [NSMutableArray arrayWithArray:[temp shuffledArray]];

이 라이브러리는 또한 창(참조하십시오 CocoaPods)

아이폰 os 에서 10 사용할 수 있습니다 있기 때문입 shuffled() 에서 GameplayKit.여기에는 도서 배열 Swift3:

import GameplayKit

extension Array {
    @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
    func shuffled() -> [Element] {
        return (self as NSArray).shuffled() as! [Element]
    }
    @available(iOS 10.0, macOS 10.12, tvOS 10.0, *)
    mutating func shuffle() {
        replaceSubrange(0..<count, with: shuffled())
    }
}

는 경우 요소가 반복됩니다.

예:배열:A A A B B B B A A A

유일한 솔루션입니다:A B A B A

sequenceSelected 는 NSMutableArray 는 매장의 요소 등 obj,포 일부 순서에 있습니다.

- (void)shuffleSequenceSelected {
    [sequenceSelected shuffle];
    [self shuffleSequenceSelectedLoop];
}

- (void)shuffleSequenceSelectedLoop {
    NSUInteger count = sequenceSelected.count;
    for (NSUInteger i = 1; i < count-1; i++) {
        // Select a random element between i and end of array to swap with.
        NSInteger nElements = count - i;
        NSInteger n;
        if (i < count-2) { // i is between second  and second last element
            obj *A = [sequenceSelected objectAtIndex:i-1];
            obj *B = [sequenceSelected objectAtIndex:i];
            if (A == B) { // shuffle if current & previous same
                do {
                    n = arc4random_uniform(nElements) + i;
                    B = [sequenceSelected objectAtIndex:n];
                } while (A == B);
                [sequenceSelected exchangeObjectAtIndex:i withObjectAtIndex:n];
            }
        } else if (i == count-2) { // second last value to be shuffled with last value
            obj *A = [sequenceSelected objectAtIndex:i-1];// previous value
            obj *B = [sequenceSelected objectAtIndex:i]; // second last value
            obj *C = [sequenceSelected lastObject]; // last value
            if (A == B && B == C) {
                //reshufle
                sequenceSelected = [[[sequenceSelected reverseObjectEnumerator] allObjects] mutableCopy];
                [self shuffleSequenceSelectedLoop];
                return;
            }
            if (A == B) {
                if (B != C) {
                    [sequenceSelected exchangeObjectAtIndex:i withObjectAtIndex:count-1];
                } else {
                    // reshuffle
                    sequenceSelected = [[[sequenceSelected reverseObjectEnumerator] allObjects] mutableCopy];
                    [self shuffleSequenceSelectedLoop];
                    return;
                }
            }
        }
    }
}
NSUInteger randomIndex = arc4random() % [theArray count];

Kristopher 존슨의 응답 은 꽤 좋은,그러나 그것은 완전히 무작위입니다.

주어진 배열의 2 요소,이 기능을 반환 항상 역 편하고 있기 때문에,생성 범위를 임의의 나머지 인덱스입니다.더 정확한 shuffle() 기능 같은 것입

- (void)shuffle
{
   NSUInteger count = [self count];
   for (NSUInteger i = 0; i < count; ++i) {
       NSInteger exchangeIndex = arc4random_uniform(count);
       if (i != exchangeIndex) {
            [self exchangeObjectAtIndex:i withObjectAtIndex:exchangeIndex];
       }
   }
}

편집: 이것은 올바르지 않습니다. 에 대한 참조 목적으로하지 않았다,삭제합니다.에 대한 의견을 참조하십시오 왜 이 방법은 정확하지 않습니다.

여기에 간단한 코드:

- (NSArray *)shuffledArray:(NSArray *)array
{
    return [array sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        if (arc4random() % 2) {
            return NSOrderedAscending;
        } else {
            return NSOrderedDescending;
        }
    }];
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top