Chapter 19 Pg 415 Functional Programming

I’m really interested in Functional Programming, and have made it a point to use map(_:), filter(_:) etc wherever possible while following the iOS tutorials.

I chose to use filter(_:) for the following method:

func countUncheckedItems() -> Int {
  var count = 0
  for item in items where !item.checked {
    count += 1
  }
  return count
}

my method using filter(_:)

func countUncheckedItems() -> Int {
  return items.filter { item in !item.checked }.count
}

A few pages down I found that the author took a moment to make an example of this method as an intro to Functional Programing and wrote the method using reduce(_:_:) which got me thinking…

func countUncheckedItems() -> Int {
  return items.reduce(0) { cnt, item in cnt + (item.checked ? 0 : 1) }
}

I understand how to use both, but as a beginner I worry that there is a reason unbeknownst to me as to why filter was not used instead.
If it’s a matter of style / the author’s preference that’s fine.
I am just concerned that perhaps there is a situation where using filter here would fail, and reduce is the better option because it will always produce the same output - which is the goal in functional programming.

Could someone clear it up?
Thanks

I would say both ways will work reliably. The main difference is that filter builds a new list, from which you then get the count; while reduce traverses the existing list, adding a 1 or a 0 to the running total. So reduce does not build a new list, which means less memory use. Reduce is arguably a more direct expression of your intention here, which is also a goal of functional programming.

1 Like

ahh!!! Brilliant! Thank you so much for your reply!
I’m SUPER interested in functional programming.

So would you consider it self mutating?
I’m making a correlation between it being named reduce(), not reduced() and sort() (which self mutates) vs sorted() which will make a new array?

Again thanks so much!

No, Reduce does not change the array, and does not return an array either. It returns a single value, the result of calling the closure for each element in the array. Filter also does not mutate, it returns a new array.

The dual syntax ala “sort” and “sorted” seems to occur when it could either change the array or return a new array.

1 Like

Understood.
tbh reduce() is the weakest of all my understandings of Swift’s first class funcs - my exposure to it has been simple: sum arrays/sequences so I wasn’t at all excited about it. Your info is much appreciated, I have a new respect and interest in reduce(_:) :+1:

I prefer the trailing closure syntax with shorthand param/arg names because the patterns seem clearer to me. I was able to fool around with reduce and get this to do the same desired affect as the author’s reduce with param names.

  func countUncheckedItems() -> Int {
    return items.reduce(0) { $0 + ($1.checked ? 0 : 1) }
  }

In terms of sort(by:): Chapter 19, pg 417

The Author's code
func sortChecklists() {
  lists.sort(by: { (checklist1, checklist2) -> Bool in
    return checklist1.name.localizedStandardCompare(checklist2.name) == .orderedAscending })
}

I thought conforming lists type Checklist to Comparable would be awesome so that I could REALY simplify the sort(by:) method

extension Checklist: Comparable & implementation
extension Checklist: Comparable {
  static func < (lhs: Checklist, rhs: Checklist) -> Bool {
    return lhs.name < rhs.name
  }
}

func sortChecklists() {
  return lists.sort(by: <)
}

My thoughts are either that the author did not wish to go into details on how to implement an Equatable/Conformable protocol, or that there is a good reason why it was written as such.

I have never seen the method .localizedStandardCompare before and the Documentation states it’s a Generic instant Method on StringProtocol.

Is it used primarily if the coder does not expect to utilize Comparable more than once? Is having Checklist adopt the protocol overkill?

I think the reason not to adopt Comparable as you have suggested is that CheckListItems don’t have a natural sort order. CheckListItems could be sorted by name, or by date, or by checked and then date, and so on. Comparable is usually for things that act like a single value and have one natural way to sort them.

.localizedStandardCompare is from NSString, and makes file name comparisons the same in different locales. I don’t think it is needed here; swift lets you just use operators:
a.name < b.name

1 Like

Ah, I see.
Thank you very much for clearing all of this up, I have learned so much!

For anyone interested, here are 2 ways to write the sortChecklists() definition with trailing syntax & shorthand parameters/arguments:

  func sortChecklists() {
    return lists.sort(by: { $0.name < $1.name } )
  }
  
  func sortChecklists() {
    return lists.sort { $0.name < $1.name }
  }
1 Like

This topic was automatically closed after 166 days. New replies are no longer allowed.