Nazmul Hasan
Nazmul Hasan

Reputation: 10600

How can split from string to array by chunks of given size

I want to split string by chunks of given size 2

Example :

String "1234567" and output should be ["12", "34", "56","7"]

Upvotes: 5

Views: 3430

Answers (9)

Leo Dabus
Leo Dabus

Reputation: 236498

You can group your collection elements (in this case Characters) every n elements as follow:

extension Collection {
    func unfoldSubSequences(limitedTo maxLength: Int) -> UnfoldSequence<SubSequence,Index> {
        sequence(state: startIndex) { start in
            guard start < self.endIndex else { return nil }
            let end = self.index(start, offsetBy: maxLength, limitedBy: self.endIndex) ?? self.endIndex
            defer { start = end }
            return self[start..<end]
        }
    }
    func subSequences(of n: Int) -> [SubSequence] {
        .init(unfoldSubSequences(limitedTo: n))
    }
}

let numbers = "1234567"
let subSequences = numbers.subSequences(of: 2)
print(subSequences)    // ["12", "34", "56", "7"]

edit/update:

If you would like to append the exceeding characters to the last group:

extension Collection {
    func unfoldSubSequencesWithTail(lenght: Int) -> UnfoldSequence<SubSequence,Index> {
        let n = count / lenght
        var counter = 0
        return sequence(state: startIndex) { start in
            guard start < endIndex else { return nil }
            let end = index(start, offsetBy: lenght, limitedBy: endIndex) ?? endIndex
            counter += 1
            if counter == n {
                defer { start = endIndex }
                return self[start...]
            } else {
                defer { start = end }
                return self[start..<end]
            }
        }
    }
    func subSequencesWithTail(n: Int) -> [SubSequence] {
        .init(unfoldSubSequencesWithTail(lenght: n))
    }
}

let numbers = "1234567"
let subSequencesWithTail = numbers.subSequencesWithTail(n: 2)
print(subSequencesWithTail)    // ["12", "34", "567"]

Upvotes: 10

Cristik
Cristik

Reputation: 32879

Here's a short (and clean) solution, thanks to recursion:

extension Collection {
    func chunks(ofSize size: Int) -> [SubSequence] {
        // replace this by `guard count >= size else { return [] }`
        // if you want to omit incomplete chunks
        guard !isEmpty else { return [] }
        return [prefix(size)] + dropFirst(size).chunks(ofSize: size)
    }
}

The recursion should not pose a performance problem, as Swift has support for tail call optimization.

Also if Swift arrays are really fast when it comes to prepending or appending elements (like the Objective-C ones are), then the array operations should be fast.

Thus you get both fast and readable code (assuming my array assumptions are true).

Upvotes: 1

Jano
Jano

Reputation: 63707

Swift 5

extension Array {
    func chunks(size: Int) -> [[Element]] {
        return stride(from: 0, to: count, by: size).map {
            Array(self[$0 ..< Swift.min($0 + size, count)])
        }
    }
}

extension String {
    func chunks(size: Int) -> [String] {
        map { $0 }.chunks(size: size).compactMap { String($0) }
    }
}

let s = "1234567"
print(s.chunks(size: 2)) // ["12", "34", "56", "7"]

Upvotes: 2

Tim
Tim

Reputation: 1616

There's a stupid way, you can think about the rules of the data model.

    var strOld = "123456"
    print("The original string:\(strOld)")

    strOld.insert("、", at: strOld.index(before: strOld.index(strOld.startIndex, offsetBy: 3)))

    strOld.insert("、", at: strOld.index(before: strOld.index(strOld.startIndex, offsetBy: 6)))

    print("After inserting:\(strOld)")

    let str = strOld

    let splitedArray = str.components(separatedBy: "、")
    print("After the split of the array:\(splitedArray)")

    let splitedArrayOther = str.split{$0 == "、"}.map(String.init)
    print("After break up the array (method 2):\(splitedArrayOther)")

The results:

The original string:123456
After inserting:12、34、56
After the split of the array:["12", "34", "56"]
After break up the array (method 2):["12", "34", "56"]

Upvotes: 1

Yogi
Yogi

Reputation: 3588

You can also try below code:

var arrStr: [Substring] = []
    let str = "1234567"
    var i = 0
    while i < str.count - 1 {
        let index = str.index(str.startIndex, offsetBy: i)
        //Below line gets current index and advances by 2
        let substring = str[index..<str.index(index, offsetBy: 2)]
        arrStr.append(substring)
        i += 2
    }
    if str.count % 2 == 1 {
        arrStr.append(str.suffix(1))
    }
    print(arrStr)

Upvotes: 1

Ketan Parmar
Ketan Parmar

Reputation: 27448

I have write one method in objective c as below,

-(NSMutableArray*)splitString : (NSString*)str withRange : (int)range{


NSMutableArray *arr = [[NSMutableArray alloc]init];

NSMutableString *mutableStr = [[NSMutableString alloc]initWithString:str];

int j = 0;
int counter = 0;

for (int i = 0; i < str.length; i++) {

    j++;

    if (range == j) {

        j = 0;


        if (!(i == str.length - 1)) {

             [mutableStr insertString:@"$" atIndex:i+1+counter];
        }



        counter++;
    }
}



arr = (NSMutableArray*)[mutableStr componentsSeparatedByString:@"$"];

NSLog(@"%@",arr);

return arr;
}

You can call this method like,

 [self splitString:@"123456" withRange:2];

and result will be,

(
12,
34,
56
)

Upvotes: 1

iOS Geek
iOS Geek

Reputation: 4855

try this

func SplitString(stringToBeSplitted:String, By:Int) -> [String]
    {
        var newArray = [String]()
        var newStr = String()
        for char in stringToBeSplitted
        {
            newStr += String(char)
            if newStr.count == By
            {
                newArray.append(newStr)
                newStr = ""
            }

        }
        return newArray
    }

Upvotes: 2

Shahrukh
Shahrukh

Reputation: 752

extension String {
    func split(len: Int) -> [String] {
        var currentIndex = 0
        var array = [String]()
        let length = self.characters.count
        while currentIndex < length {
            let startIndex = self.startIndex.advancedBy(currentIndex)
            let endIndex = startIndex.advancedBy(len, limit: self.endIndex)
            let substr = self.substringWithRange(Range(start: startIndex, end: endIndex))
            array.append(substr)
            currentIndex += len
        }
        return array
    }
}

"123456789".split(2)

//output: ["12", "34", "56", "78", "9"]

Upvotes: 1

Naresh
Naresh

Reputation: 17932

var testString = "abcdefghijklmnopqrstu"
var startingPoint: Int = 0
var substringLength: Int = 1
var substringArray = [AnyHashable]()
for i in 0..<(testString.count ?? 0) / substringLength {
    var substring: String = (testString as NSString).substring(with: NSRange(location: startingPoint, length: substringLength))
    substringArray.append(substring)
    startingPoint += substringLength
}
print("\(substringArray)")

OutPut : ( a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u )

Upvotes: 2

Related Questions