2015-03-08 29 views
5

मैं बिट्स के साथ सरणी है:स्विफ्ट बिट सरणी (UInt8 सरणी)

var bytes: [UInt8] 

उदाहरण के लिए मैं 280 बिट्स है और:

var bits: [Bit] 

और मैं इसे कैसे बाइट्स सरणी के लिए परिवर्तित कर सकते हैं मेरे पास बाइट्स सरणी में 35 UInt8 होना चाहिए। मैं समाधान के बारे में सोच सकता हूं जहां मैं 8 बिट लेता हूं और जांचता हूं कि क्या पहला सच है, अगर दूसरा सत्य है और तो परिणाम और मूल्य है। यह मैं अपने बिट्स सरणी में हर 8 बिट्स के लिए करता हूं। लेकिन मुझे लगता है कि यह खराब समाधान होगा (यह काम करेगा लेकिन अनावश्यक गणना के साथ)। मुझे लगता है कि कुछ स्थानांतरण के साथ तेजी से समाधान हो सकता है और इसलिए मैं इसमें वास्तव में बुरा हूं इसलिए मैं मदद की तलाश में हूं। धन्यवाद

उत्तर

7

सम्भावित समाधान सरणी में और सभी के लिए सभी बिट्स की गणना करने में है 'द वन' बिट्स UInt8 सरणी में इसी बिट सेट:

func bitsToBytes(bits: [Bit]) -> [UInt8] { 
    let numBits = bits.count 
    let numBytes = (numBits + 7)/8 
    var bytes = [UInt8](count : numBytes, repeatedValue : 0) 

    for (index, bit) in enumerate(bits) { 
     if bit == .One { 
      bytes[index/8] += 1 << (7 - index % 8) 
     } 
    } 

    return bytes 
} 

मुख्य विचार यह है कि के लिए एक दिया index बिट सरणी में, index/8 बाइट सरणी में संबंधित इंडेक्स है, और index % 8 बाइट में बिट स्थिति है। वांछित बिट ऑर्डर के आधार पर index % 8 या 7 - index % 8 शिफ्ट राशि के रूप में उपयोग कर सकते हैं।

उदाहरण:

// 0110 0100 0000 1001 
let bits : [Bit] = [.Zero, .One, .One, .Zero, .Zero, .One, .Zero, .Zero, .Zero, .Zero, .Zero, .Zero, .One, .Zero, .Zero, .One] 
let bytes = bitsToBytes(bits) 
println(bytes) // [100, 9] 

वैकल्पिक रूप से, आप "इनलाइन" 8 बिट के प्रत्येक समूह के के लिए गणना कर सकते हैं। आपको यह जांचना होगा कि कौन सा समाधान आपके मामले में बेहतर प्रदर्शन करता है।

func bitsToBytes(bits: [Bit]) -> [UInt8] { 
    let numBits = bits.count 
    let numBytes = numBits/8 
    var bytes = [UInt8](count : numBytes, repeatedValue : 0) 
    for pos in 0 ..< numBytes { 
     let val = 128 * bits[8 * pos].toIntMax() + 
      64 * bits[8 * pos + 1].toIntMax() + 
      32 * bits[8 * pos + 2].toIntMax() + 
      16 * bits[8 * pos + 3].toIntMax() + 
      8 * bits[8 * pos + 4].toIntMax() + 
      4 * bits[8 * pos + 5].toIntMax() + 
      2 * bits[8 * pos + 6].toIntMax() + 
      1 * bits[8 * pos + 7].toIntMax() 
     bytes[pos] = UInt8(val) 
    } 
    return bytes 
} 

यहां, सादगी के लिए, यदि बिट्स की संख्या 8 से अधिक नहीं है, तो किसी भी अतिरिक्त बिट को अनदेखा कर दिया जाता है। एक ही कोड भी

func bitsToBytes(bits: [Bit]) -> [UInt8] { 
    return map(0 ..< bits.count/8) { 
     pos in 
     let val = 128 * bits[8 * pos].toIntMax() + 
      64 * bits[8 * pos + 1].toIntMax() + 
      32 * bits[8 * pos + 2].toIntMax() + 
      16 * bits[8 * pos + 3].toIntMax() + 
      8 * bits[8 * pos + 4].toIntMax() + 
      4 * bits[8 * pos + 5].toIntMax() + 
      2 * bits[8 * pos + 6].toIntMax() + 
      1 * bits[8 * pos + 7].toIntMax() 
     return (UInt8(val)) 
    } 
} 

मानक के रूप में एक सा "Swiftier" लिखा जा सकता है: यहाँ अब एक त्वरित और गंदा बेंचमार्किंग एप्लिकेशन (नीचे कोड), विभिन्न समाधान की तुलना है। यह 10,000 बिट सरणी लंबाई 256 को परिवर्तित करने का समय मापता है। परीक्षण मैकबुक प्रो 2,3 गीगाहर्ट्ज इंटेल कोर i7, और "रिलीज़" कॉन्फ़िगरेशन के साथ संकलित कोड पर किए गए थे। स्विफ्ट 1.1/Xcode 6.2 (6C131e) के साथ

परिणाम: स्विफ्ट 1.2/Xcode 6.3 (6D532l) के साथ

 
Martin1: 0.0460730195045471 
Martin2: 0.0280380249023438 
Martin3: 0.0374950170516968 
Antonio: 5.85363000631332 
Nate : 4.86936402320862 

परिणाम:

 
Martin1: 0.0228430032730103 
Martin2: 0.00573796033859253 
Martin3: 0.00732702016830444 
Antonio: 0.515677988529205 
Nate : 0.634827971458435 

कोड:

protocol BitsToBytesConverter { 
    var ident : String { get } 
    func bitsToBytes(bits: [Bit]) -> [UInt8] 
} 

class MR1 : BitsToBytesConverter { 

    let ident = "Martin1" 
    func bitsToBytes(bits: [Bit]) -> [UInt8] { 
     let numBits = bits.count 
     let numBytes = (numBits + 7)/8 
     var bytes = [UInt8](count : numBytes, repeatedValue : 0) 

     for (index, bit) in enumerate(bits) { 
      if bit == .One { 
       bytes[index/8] += UInt8(1 << (7 - index % 8)) 
      } 
     } 

     return bytes 
    } 
} 

class MR2 : BitsToBytesConverter { 

    let ident = "Martin2" 

    func bitsToBytes(bits: [Bit]) -> [UInt8] { 
     let numBits = bits.count 
     let numBytes = numBits/8 
     var bytes = [UInt8](count : numBytes, repeatedValue : 0) 
     for pos in 0 ..< numBytes { 
      let val = 128 * bits[8 * pos].toIntMax() + 
       64 * bits[8 * pos + 1].toIntMax() + 
       32 * bits[8 * pos + 2].toIntMax() + 
       16 * bits[8 * pos + 3].toIntMax() + 
       8 * bits[8 * pos + 4].toIntMax() + 
       4 * bits[8 * pos + 5].toIntMax() + 
       2 * bits[8 * pos + 6].toIntMax() + 
       1 * bits[8 * pos + 7].toIntMax() 
      bytes[pos] = UInt8(val) 
     } 
     return bytes 
    } 
} 

class MR3 : BitsToBytesConverter { 

    let ident = "Martin3" 

    func bitsToBytes(bits: [Bit]) -> [UInt8] { 
     return map(0 ..< bits.count/8) { 
      pos in 
      let val = 128 * bits[8 * pos].toIntMax() + 
       64 * bits[8 * pos + 1].toIntMax() + 
       32 * bits[8 * pos + 2].toIntMax() + 
       16 * bits[8 * pos + 3].toIntMax() + 
       8 * bits[8 * pos + 4].toIntMax() + 
       4 * bits[8 * pos + 5].toIntMax() + 
       2 * bits[8 * pos + 6].toIntMax() + 
       1 * bits[8 * pos + 7].toIntMax() 
      return (UInt8(val)) 
     } 
    } 
} 

class AB : BitsToBytesConverter { 

    let ident = "Antonio" 

    typealias IntegerType = UInt8 

    func bitsToBytes(bits: [Bit]) -> [UInt8] { 

     let initial = [IntegerType]() 

     return reduce(enumerate(bits), initial) { array, element in 
      // The size in bits of a UInt8 
      let size = sizeof(IntegerType) * 8 

      // Create a mutable copy of the array returned at the previous iteration 
      var next = array 

      // If it's the first iteration, or an iteration divisible by the size of UInt8, 
      // append a new element to the array 
      if element.index % size == 0 { 
       next.append(0x00) 
      } 

      // Shift all bits of the last element to the left 
      next[next.count - 1] <<= 1 

      // If the current bit is one, add 1 to the rightmost bit 
      // Using a logical OR 
      if element.element == .One { 
       next[next.count - 1] |= 0x01 
      } 

      return next 
     } 
    } 
} 

class NC : BitsToBytesConverter { 

    let ident = "Nate " 

    func group<T>(array: [T], byCount groupCount: Int) -> [Slice<T>] { 
     // get a list of the start indices 
     let startIndices = stride(from: 0, to: array.count, by: groupCount) 
     // add `groupCount` to each to get the end indices 
     let endIndices = lazy(startIndices).map { advance($0, groupCount, array.count) } 

     // zip those together & map onto an array of slices of the input array 
     return map(Zip2(startIndices, endIndices)) { 
      array[$0.0 ..< $0.1] 
     } 
    } 

    func bitsToByte(bits: Slice<Bit>) -> UInt8 { 
     return bits.reduce(0) { accumulated, current in 
      accumulated << 1 | (current == .One ? 1 : 0) 
     } 
    } 

    func bitsToBytes(bits: [Bit]) -> [UInt8] { 
     return group(bits, byCount: 8).map(bitsToByte) 
    } 
} 


let numBits = 256 // Bits per bit array 
let numBitArrays = 10000 // Number of bit arrays 

func randomBits() -> [Bit] { 
    return map(0 ..< numBits) { _ in 
     Bit(rawValue: Int(arc4random_uniform(2)))! 
    } 
} 

func randomBitsArray() -> [[Bit]] { 
    return map(0 ..< numBitArrays) { _ in 
     randomBits() 
    } 
} 

let bitsArray = randomBitsArray() 

func test(conv : BitsToBytesConverter) { 
    let x = conv.bitsToBytes([]) 
    let startTime = NSDate() 
    for bits in bitsArray { 
     let bytes = conv.bitsToBytes(bits) 
    } 
    let duration = -startTime.timeIntervalSinceNow 
    println("\(conv.ident): \(duration)") 
} 

test(MR1()) 
test(MR2()) 
test(MR3()) 
test(AB()) 
test(NC()) 
+0

पहली विधि बिल्कुल वही है जो मैं ढूंढ रहा था। धन्यवाद –

+0

दिलचस्प परिणाम ... स्विफ्ट 1.2 के साथ तुलना करना अच्छा लगेगा, मुझे विशेष रूप से सबसे धीमे लोगों के लिए ध्यान देने योग्य सुधार की उम्मीद है - मैं खुद कर सकता हूं, लेकिन परिणाम एचडब्ल्यू/एसड मतभेदों के कारण विभिन्न मीट्रिक पर आधारित होंगे। – Antonio

+0

@ एंटोनियो: अच्छा विचार, किया गया। –

2

हैं आप अधिक महंगी गणना की लागत पर एक कार्यात्मक दृष्टिकोण पसंद करते हैं, तो आप reduce का उपयोग संयोजन में कर सकते हैं enumerate के साथ आयन।

उत्तरार्द्ध, तत्वों का अनुक्रम दिया गया, (index, element) tuples का अनुक्रम बनाता है। हमें बिट स्थिति जानने के लिए सूचकांक की आवश्यकता है।

reduce बजाय UInt8

typealias IntegerType = UInt8 

let initial = [IntegerType]() 

let result = reduce(enumerate(bits), initial) { array, element in 
    // The size in bits of a UInt8 
    let size = sizeof(IntegerType) * 8 

    // Create a mutable copy of the array returned at the previous iteration 
    var next = array 

    // If it's the first iteration, or an iteration divisible by the size of UInt8, 
    // append a new element to the array 
    if element.index % size == 0 { 
     next.append(0x00) 
    } 

    // Shift all bits of the last element to the left 
    next[next.count - 1] <<= 1 

    // If the current bit is one, add 1 to the rightmost bit 
    // Using a logical OR 
    if element.element == .One { 
     next[next.count - 1] |= 0x01 
    } 

    return next 
} 

प्राप्त परिणाम का एक सरणी में Bit की एक सरणी कम करने के लिए प्रयोग किया जाता है UInt8 की एक सरणी है।

अद्यतन है कि अगर आप एक अलग पूर्णांक प्रकार के लिए परिवर्तित करना चाहते हैं, बस IntegerType उपनाम परिवर्तित उल्लेख करना भूल।

+0

* "अधिक महंगा गणना की लागत पर" * - आप सही हैं। मैंने कुछ मानक बनाए और यह गैर-कार्यात्मक दृष्टिकोण की तुलना में लगभग 100 गुना धीमा था :) –

+0

@ मार्टिनआर: वाह, मैं काफी हैरान हूं - मुझे 2-10x की सीमा में कुछ उम्मीद थी, लेकिन 100 नहीं! निस्संदेह क्या अधिक लागत सरणी प्रतिलिपि है, जो हर बिट के लिए किया जाता है - और यह एक वास्तविक प्रति है, क्योंकि सरणी को परिवर्तनीय बनाया गया है और इसे – Antonio

+0

पर उत्परिवर्तित किया गया है मैंने बेंचमार्किंग कोड और परिणाम जोड़े हैं। –

3

यह एक मजेदार सवाल है। मैं इसे दो छोटी समस्याओं के रूप में देखता हूं: (1) Bit की सरणी को Bit सरणी की सरणी में विभाजित करने के लिए, जहां प्रत्येक छोटी सरणी एक बाइट के लाइट्स के लायक है, और (2) उन छोटे सरणी को एक बाइट में कैसे परिवर्तित करें से प्रत्येक।

पहले हल करने के लिए, हम एक समारोह लिख सकते हैं कि एक विशेष आकार के टुकड़ों में समूहों एक सरणी:

func group<T>(array: [T], byCount groupCount: Int) -> [Slice<T>] { 
    // get a list of the start indices 
    let startIndices = stride(from: 0, to: s.count, by: groupCount) 
    // add `groupCount` to each to get the end indices 
    let endIndices = lazy(startIndices).map { advance($0, groupCount, array.count) } 

    // zip those together & map onto an array of slices of the input array 
    return map(zip(startIndices, endIndices)) { 
     array[$0.0 ..< $0.1] 
    } 
} 

दूसरा हल करने के लिए, हम एक समारोह है कि प्रत्येक Slice<Bit>group(_:byCount:) से लौटे लेता लिख ​​सकते हैं और इसे UInt8 में परिवर्तित करता है। हर कदम यह मूल्य एक बिट द्वारा छोड़ा बदलाव पर, तो लोगों बिट सेट करता है, तो उस तत्व .One है:

func bitsToByte(bits: Slice<Bit>) -> UInt8 { 
    return bits.reduce(0) { accumulated, current in 
     accumulated << 1 | (current == .One ? 1 : 0) 
    } 
} 

अंत में, आप बदले में इनमें से प्रत्येक फोन, या उन्हें गठजोड़ कर सकते हैं अपने परिणाम प्राप्त करने के:

// 1111 1111 1000 0000 0000 0001 0101 0101 
let bits : [Bit] = [.One, .One, .One, .One, .One, .One, .One, .One, 
    .One, .Zero, .Zero, .Zero, .Zero, .Zero, .Zero, .Zero, 
    .Zero, .Zero, .Zero, .Zero, .Zero, .Zero, .Zero, .One, 
    .Zero, .One, .Zero, .One, .Zero, .One, .Zero, .One] 
let bytes = group(bits, byCount: 8).map(bitsToByte) 
// [255, 128, 1, 85] 
+0

's.count' शायद' array.count' होना चाहिए? - (बीटीडब्ल्यू, मैंने कुछ मानक बनाए और यह पता चला कि यह गैर-कार्यात्मक समाधानों की तुलना में काफी धीमी है।) –

+0

धन्यवाद, तय! गति के बारे में बहुत बुरा-उम्मीद कर रहा था कि 'स्लाइस' का उपयोग करके इसे बराबर रखा जाएगा क्योंकि सरणी को प्रतिलिपि बनाने की आवश्यकता नहीं है। क्या आपके पास कहीं भी आपका बेंचमार्क कोड है जो मैं देख सकता था? –

+0

मैंने कोड और परिणाम जोड़े हैं। –

1

यहाँ कुछ शांत कोड @ मार्टिन-r @antonio @ नैट-पकाना, लेकिन वहाँ भी कुछ सही होने के मुद्दों है कि मैं अपने उपयोग के लिए स्विफ्ट 3लिए इस कोड को परिवर्तित करते हुए की खोज की हो रहा है। इस संशोधित स्निपेट की सुविधा: एक खेल का मैदान

  • में

    • Xcode 8, स्विफ्ट 3.0, रन के रूप में मान्यता क्षमता (बाहर टिप्पणी की)
    • बिट enum बिट प्रकार का प्रतिनिधित्व करने के है भी शामिल है। (बिट प्रकार को स्विफ्ट 3 से हटा दिया गया था)
    • हालांकि इसमें अभी भी समय उपकरण है, मैंने वास्तव में विभिन्न तरीकों की गति का परीक्षण करने की कोशिश नहीं की है। ऐसा लगता है कि हमें पहले सही परिणाम सुनिश्चित करने की आवश्यकता है।
    • केवल मार्टिन 1 और मार्टिन 2 कोडित। अन्य विधियों को पाठक के लिए अभ्यास के रूप में छोड़ दिया;)।
    Martin1: 0.112455010414124: hash 0 
    Martin2: 1.06640499830246: hash 0 
    

    वैसे भी, यहाँ मेरी कोड जोरदार आधार पर दूसरों का काम है। उम्मीद है कि कुछ इसे उपयोगी पाते हैं।

    import Foundation 
    
    enum Bit { case zero, one 
        func asInt() -> Int { 
         return (self == .one) ? 1 : 0 
        } 
    } 
    
    protocol BitsToBytesConverter { 
        var ident : String { get } 
        func bitsToBytes(bits: [Bit]) -> [UInt8] 
    } 
    
    class MR1 : BitsToBytesConverter { 
    
        let ident = "Martin1" 
    
        func bitsToBytes(bits: [Bit]) -> [UInt8] { 
         assert(bits.count % 8 == 0, "Bit array size must be multiple of 8") 
    
         let numBytes = 1 + (bits.count - 1)/8 
         var bytes = [UInt8](repeating: 0, count: numBytes) 
    
         for (index, bit) in bits.enumerated() { 
          if bit == .one { 
           bytes[index/8] += UInt8(1 << (7 - index % 8)) 
          } 
         } 
         return bytes 
        } 
    } 
    
    class MR2 : BitsToBytesConverter { 
    
        let ident = "Martin2" 
    
        func bitsToBytes(bits: [Bit]) -> [UInt8] { 
         assert(bits.count % 8 == 0, "Bit array size must be multiple of 8") 
    
         let numBytes = 1 + (bits.count - 1)/8 
    
         var bytes = [UInt8](repeating : 0, count : numBytes) 
         for pos in 0 ..< numBytes { 
          let val = 128 * bits[8 * pos].asInt() + 
           64 * bits[8 * pos + 1].asInt() + 
           32 * bits[8 * pos + 2].asInt() + 
           16 * bits[8 * pos + 3].asInt() + 
           8 * bits[8 * pos + 4].asInt() + 
           4 * bits[8 * pos + 5].asInt() + 
           2 * bits[8 * pos + 6].asInt() + 
           1 * bits[8 * pos + 7].asInt() 
          bytes[pos] = UInt8(val) 
         } 
         return bytes 
        } 
    } 
    
    func format(bits: [Bit]) -> String { 
        return bits.reduce("") { (current, next) in 
         return current.appending((next == .one) ? "1" : "0") 
        } 
    } 
    func randomBits(ofLength: Int) -> [Bit] { 
        return (0 ..< ofLength).map() { _ in 
         Int(arc4random_uniform(2)) == 1 ? .one : .zero 
        } 
    } 
    func isValid(conv: BitsToBytesConverter, input: [Bit], expected: [UInt8]) -> Bool { 
        let actual = conv.bitsToBytes(bits: input) 
        var bIsValid = (actual.count == expected.count) 
        if bIsValid { 
         for index in 0 ..< expected.count { 
          if actual[index] != expected[index] { 
           bIsValid = false 
           break 
          } 
         } 
        } 
        return bIsValid 
    } 
    func validateAll() { 
        let input0: [Bit] = [.one, .zero, .one, .zero, .one, .zero, .one, .zero] 
        let expected0: [UInt8] = [170] 
    
        let input1: [Bit] = (0..<8).map { _ in .zero } 
        let expected1: [UInt8] = [0] 
    
        let input2: [Bit] = (0..<8).map { _ in .one } 
        let expected2: [UInt8] = [255] 
    
        let input3 = input1 + input2 
        let expected3 = expected1 + expected2 
    
        let input4 = input2 + input1 
        let expected4 = expected2 + expected1 
    
        let inputs = [input0, input1, input2, input3, input4] 
        let expecteds = [expected0, expected1, expected2, expected3, expected4] 
    
        let convs: [BitsToBytesConverter] = [MR1(), MR2()] 
    
        for inIndex in 0 ..< inputs.count { 
         let input = inputs[inIndex] 
         let expected = expecteds[inIndex] 
    
         let formattedBits = format(bits: input) 
         print("Checking: \(formattedBits) -> \(expected)") 
    
         for conv in convs { 
          let bIsValid = isValid(conv: conv, input: input, expected: expected) 
          print("\(conv.ident) valid = \(bIsValid)") 
         } 
        } 
    } 
    func timeTest(conv : BitsToBytesConverter, bitsArray: [[Bit]]) { 
        // Prime compilation, caching, ... 
        let _ = conv.bitsToBytes(bits: bitsArray[0]) 
    
        let startTime = NSDate() 
        var hash = 0 
    
        for bits in bitsArray { 
         let _ = conv.bitsToBytes(bits: bits) 
    
         // Hash to compare results across methods 
         //let result = conv.bitsToBytes(bits: bits) 
         //let bString = format(bits: bits) 
         //print("Bits: \(bString): Bytes: \(result)") 
         //hash = result.reduce(0) { (previous, next) in 
         // return previous + next.hashValue 
         //} 
        } 
        let duration = -startTime.timeIntervalSinceNow 
        print("\(conv.ident): \(duration): hash \(hash)") 
    } 
    func testAll() { 
        let numBits = 128 // Bits per bit array 
        let numBitArrays = 100 // Number of bit arrays 
    
        let testValues = (0 ..< numBitArrays).map() { _ in 
         randomBits(ofLength: numBits) 
        } 
        timeTest(conv: MR1(), bitsArray: testValues) 
        timeTest(conv: MR2(), bitsArray: testValues) 
    } 
    //validateAll() 
    testAll() 
    
  • संबंधित मुद्दे