Skip to content

Conversation

shimesaba9
Copy link

No description provided.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not actually the right way to do this, because it's O(n^2). See http://airspeedvelocity.net/2015/08/03/arrays-linked-lists-and-performance/ for details. You should switch to using a temporary array and a plain old for loop, despite the ugliness.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rothomp3 beat me to it :) yes reduce can really suffer performance-wise. here's an elegant answer I stumbled upon a few month back (it's a global function in this case, but making it into a protocol extension is trivial)

func uniq<S: SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] {
  var seen = [E: Bool]()
  return source.filter { seen.updateValue(true, forKey: $0) == nil }
}

http://stackoverflow.com/a/33984316/870155

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dictionary is probably unnecessary - there's no need to store the Bool values. You could do the same with just a Set:

extension SequenceType where Generator.Element : Hashable {

  public func uniq() -> [Generator.Element] {
    var prevs: Set<Generator.Element> = []
    return filter { el in
      if prevs.contains(el) { return false }
      prevs.insert(el)
      return true
    }
  }
}

Which is maybe a little more efficient. Both the Dictionary and Set versions translate easily into a lazy method:

extension LazySequenceType where Generator.Element : Hashable {

  public func uniq() -> LazyFilterSequence<Self> {
    var prevs: Set<Generator.Element> = []
    return lazy.filter { el in
      if prevs.contains(el) { return false }
      prevs.insert(el)
      return true
    }
  }
}

However, there's another problem with these implementations: they rely on side-effects from filter's closure, which is generally discouraged (I think). For instance, the function would be broken if the closure was evaluated more than once, or in a different order. So it's maybe best to have a more imperative for loop:

extension SequenceType where Generator.Element : Hashable {

  public func uniq() -> [Generator.Element] {
    var prevs: Set<Generator.Element> = []
    var uniqs: [Generator.Element] = []
    for el in self where !prevs.contains(el) {
      prevs.insert(el)
      uniqs.append(el)
    }
    return uniqs
  }
}

But then the lazy version would need to be more complex as well. (You'd probably have to write a custom struct, similar to the standard library's LazyFilterSequence. This is the kind of thing I mean)

Considering all that, I'm not sure what the function or method would add over just using the standard Set initialiser. The order of the elements is retained, and there's a possible lazy version, but it's a lot of extra complexity for maybe not much extra functionality.

@gribozavr
Copy link
Contributor

Thank you for your PR. This is a change to the library API, so it should follow the Swift Evolution Process. Please write an informal proposal and send it to swift-evolution@swift.org.

@gribozavr gribozavr added the swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review label Dec 4, 2015
@tkremenek
Copy link
Member

Closing because this is not how we propose library changes.

@tkremenek tkremenek closed this Dec 4, 2015
@shimesaba9
Copy link
Author

I got it.
Thank you for review.

slavapestov pushed a commit to slavapestov/swift that referenced this pull request Nov 27, 2018
SR-2856: adapt dispatch_timer_set_time for CI
dabelknap added a commit to dabelknap/swift that referenced this pull request Jan 11, 2019
Fix formatting of empty type declarations.
maldahleh pushed a commit to maldahleh/swift that referenced this pull request Oct 26, 2020
…ials

[Syntax] Rename the `as` conversion functions that incur existential conversions to `asProtocol`
@AnthonyLatsis AnthonyLatsis removed the swift evolution pending discussion Flag → feature: A feature that has a Swift evolution proposal currently in review label Mar 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants