简体   繁体   中英

Swift 4 Filter an array based on a condition and a count

class Bar {
    var data: Int = 0
    var sent = false
}

var fooArray: [Bar] = []

I have an array of data values that are periodically sent to a server. After the server acknowledges the receipt of the data my code goes through and removes all of the items in the array that were sent. I know I can remove all of the sent items with a simple filter:

fooArray = fooArray.filter { $0.sent != true }

But now I want to keep 100 items in the array regardless of whether they have been sent or not. I know I can write a loop to do this, but I'm wondering if there's a more Swifty way.

Given you class (with the uppercase B)

class Bar {
    var data = 0
    var sent = false
}

and an array

let bars: [Bar] = ...

You can get a filtered array containing

  1. all the unsent bars
  2. plus the sent bars to reach the number of 100

Here's the code

let filtered = bars.reduce([Bar]()) { (res, bar) -> [Bar] in
    if !bar.sent || res.count < 100 {
        return res + [bar]
    }
    return res
}

If I understand correctly you want to keep all unsent items (even if there are more than 100) but also keep sent items up to a total that does not exceed 100 from unsent items.

If the order of items doesn't need to be preserved, you can use a sort to group the items placing the unsent ones first and then filter them keeping sent ones only if they are at a position below 100.

fooArray = fooArray.sorted{($0.sent ? 1:0) < ($1.sent ? 1:0)} //unsent first
                   .enumerated()                              // get indexes
                   .filter{ !$1.sent || $0 < 100 } // keep unsent or below 100
                   .map{$1}

You could partition the array into unsent and sent items and then take the first 100:

partition is a mutating function that takes a closure which determines which items go to the second part of the array. This turns push all the sent items to the back of the array. You can then take the first 100 items of this array, which will have the unsent items at the front and the sent items in the bottom part of the array. If there are less than 100 items, it shows the whole array.

fooArray.partition{ $0.sent }
fooArray = fooArray.prefix(100)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM