Home > OS >  how to only remove 3 of 5 specific items of an array swift
how to only remove 3 of 5 specific items of an array swift

Time:11-09

I have an array

var arr = ["car", "car", "bike", "bus", "car", "car", "car"]

When I try to filter :

var newArr = arr.filter { $0 != "car" }

It removes all 5 cars, I only need to remove 3

I want new array to be:

["bike", "bus", "car", "car"]

CodePudding user response:

You can simply add a counter and check the condition inside your filter predicate:


var arr = ["car", "car", "bike", "bus", "car", "car", "car"]

var counter = 3
var newArr = arr.filter {
    if counter > 0, $0 == "car" {
        counter -= 1
        return false
    }
    return true
}

print(newArr)

This will print:

["bike", "bus", "car", "car"]


If you would like to implement a removeAll(where:) method with the option to limit the number of elements removed you can implement something like:

extension RangeReplaceableCollection {
    mutating func removeAll(where predicate: ((Element) -> Bool), limitedTo counter: Int) {
        var counter = counter
        removeAll {
            if counter > 0, predicate($0) {
                counter -= 1
                return true
            }
            return false
        }
    }
}

Usage:

var arr = ["car", "car", "bike", "bus", "car", "car", "car"]
arr.removeAll(where: { $0 == "car"}, limitedTo: 3)
print(arr)  // "["bike", "bus", "car", "car"]\n"

CodePudding user response:

If you want to delete the first 3 elements only if the number of occurrences exceeds 3, then here a generic function that does what you need:

func removeExactly<T: Equatable>(
  theFirst k: Int,
  occurencesOf element: T,
  from a: [T]
) -> [T] {
    guard k >= 0 else {
        fatalError("k has to be non-negative")
    }

    if k == 0 { return a }
    
    let n = a.count
    var indices = [Int]()

    for i in 0..<n where a[i] == element {
        indices.append(i)
        if indices.count == k { break }
    }

    //Make sure that we've found k occurrences
    if indices.count != k { return a }

    //Join the array slices excluding the k first occurrences of element
    indices.append(n)
    var ans = Array(a[0..<indices[0]])
    for j in 1..<indices.count {
        let start = indices[j - 1]   1
        let end = indices[j]
        ans  = a[start..<end]
    }

    return ans
}

Here are some test cases:

var arr = ["car", "car", "bike", "bus", "car", "car", "car"]

print(removeExactly(theFirst: 3,  occurencesOf: "car",  from: arr))
//["bike", "bus", "car", "car"]

print(removeExactly(theFirst: 10, occurencesOf: "car",  from: arr))
//["car", "car", "bike", "bus", "car", "car", "car"]

print(removeExactly(theFirst: 1,  occurencesOf: "bike", from: arr))
//["car", "car", "bus", "car", "car", "car"]

print(removeExactly(theFirst: 2,  occurencesOf: "bike", from: arr))
//["car", "car", "bike", "bus", "car", "car", "car"]
  • Related