2014-12-22 2 views
4

배열에서 가장 일반적인 (모달) 요소를 찾아야합니다.가장 일반적인 배열 요소

내가 생각할 수있는 가장 단순한 방법은 각 고유 요소에 대해 변수를 설정하고 각각에 대해 개수 변수를 할당하는 것이 었습니다.이 변수는 배열을 통해 실행되는 for 루프에 기록 될 때마다 증가합니다.

배열의 크기는 알 수 없으므로 매우 클 것이므로이 방법은 쓸모가 없습니다.

NSCountedSet 메서드를 사용하여 배열 요소의 순위를 매기는 비슷한 질문이 Objective-C에서 발견되었습니다. 불행히도 나는 프로그래밍에 익숙하지 않으며 첫 번째 라인 만 Swift로 번역 할 수 있습니다. 다음과 같이

제안 된 방법은 다음과 같습니다

var yourArray: NSArray! // My swift translation 

    NSCountedSet *set = [[NSCountedSet alloc] initWithArray:yourArray]; 

    NSMutableDictionary *dict=[NSMutableDictionary new]; 

    for (id obj in set) { 
     [dict setObject:[NSNumber numberWithInteger:[set countForObject:obj]] 
      forKey:obj]; //key is date 
    } 

    NSLog(@"Dict : %@", dict); 

    NSMutableArray *top3=[[NSMutableArray alloc]initWithCapacity:3]; 

    //which dict obj is = max 
    if (dict.count>=3) { 

     while (top3.count<3) { 
      NSInteger max = [[[dict allValues] valueForKeyPath:@"@max.intValue"] intValue]; 

      for (id obj in set) { 
       if (max == [dict[obj] integerValue]) { 
        NSLog(@"--> %@",obj); 
        [top3 addObject:obj]; 
        [dict removeObjectForKey:obj]; 
       } 
      } 
     } 
    } 

    NSLog(@"top 3 = %@", top3); 

내 프로그램에서 내가 배열에서 상위 5 곳의 이름을 찾아야합니다.

+0

"상위 5 개"란 무엇을 의미합니까? 배열에 동일한 요소가 여러 번 포함되어 있습니까? 가장 많이 찾는 사람들을 알고 싶습니까? –

+0

배열에는 사용자가 체크인 한 도시 이름 목록이 포함됩니다. 사용자가 체크인 한 다섯 자리를 가장 많이 출력하도록 배열의 요소를 정렬해야합니다. 그래서 yes 배열에 요소가 여러 번 반복 될 것입니다 – TimWhiting

답변

14

편집 : 지금

솔루션을 가장 효율적으로하지

하지만 간단한 아래 스위프트 2.0 :

let a = [1,1,2,3,1,7,4,6,7,2] 

var frequency: [Int:Int] = [:] 

for x in a { 
    // set frequency to the current count of this element + 1 
    frequency[x] = (frequency[x] ?? 0) + 1 
} 

let descending = sorted(frequency) { $0.1 > $1.1 } 

descending 지금 쌍 배열로 구성 값과 주파수, 정렬 가장 자주. 따라서 "상위 5"는 처음 5 개의 항목이됩니다 (5 개 이상의 고유 한 값이 있다고 가정) . 소스 배열이 얼마나 큰지는 중요하지 않습니다.

extension SequenceType where Generator.Element: Hashable { 
    func frequencies() -> [(Generator.Element,Int)] { 

     var frequency: [Generator.Element:Int] = [:] 

     for x in self { 
      frequency[x] = (frequency[x] ?? 0) + 1 
     } 

     return frequency.sort { $0.1 > $1.1 } 
    } 
} 

a.frequencies() 

스위프트의 경우 :

func frequencies 
    <S: SequenceType where S.Generator.Element: Hashable> 
    (source: S) -> [(S.Generator.Element,Int)] { 

    var frequency: [S.Generator.Element:Int] = [:] 

    for x in source { 
     frequency[x] = (frequency[x] ?? 0) + 1 
    } 

    return sorted(frequency) { $0.1 > $1.1 } 
} 

frequencies(a) 

스위프트 2.0를 들어, 프로토콜의 확장으로 기능을 적용 할 수 있습니다 : 여기

어떤 순서에 일하는 것이 일반적인 기능 버전입니다 3.0 :

extension Sequence where Self.Iterator.Element: Hashable { 
    func frequencies() -> [(Self.Iterator.Element,Int)] { 

     var frequency: [Self.Iterator.Element:Int] = [:] 

     for x in self { 
      frequency[x] = (frequency[x] ?? 0) + 1 
     } 

     return frequency.sorted { $0.1 > $1.1 } 
    } 
} 
+4

if-let-else는 'frequency [x] = 1 + (frequency [x] ??0)' –

+0

thx가 이것을 수정했습니다 –

+0

Swift 3 구문은 무엇입니까? –

2

XCode 7.1의 경우 솔루션입니다. reduce 대신 for-in의를 사용하여 대기 속도 속도와 동일

// Array of elements 
let a = [7,3,2,1,4,6,8,9,5,3,0,7,2,7] 

// Create a key for elements and their frequency 
var times: [Int: Int] = [:] 

// Iterate over the dictionary 
for b in a { 
    // Every time there is a repeat value add one to that key 
    times[b] = (times[b] ?? 0) + 1 
} 

// This is for sorting the values 
let decending = times.sort({$0.1 > $1.1}) 
// For sorting the keys the code would be 
// let decending = times.sort({$0.0 > $1.0}) 
// Do whatever you want with sorted array 
print(decending) 
0

:

extension Sequence where Self.Iterator.Element: Hashable { 
    func frequencies() -> [(Self.Iterator.Element, Int)] { 
     return reduce([:]) { 
      var frequencies = $0 
      frequencies[$1] = (frequencies[$1] ?? 0) + 1 
      return frequencies 
     }.sorted { $0.1 > $1.1 } 
    } 
} 

하지만, 여기에 그주의하시기 바랍니다 때문에 구조체 복사 비용의 using reduce with a struct is not as efficient as a for-in. 따라서 일반적으로 for-in 방법을 선호합니다.

[편집 :이 글은 최상위 답변과 같은 녀석입니다!]