1

I'd like to write a method that takes either a Set or Array,

like a Collection-conforming parameter, or something like that

The problem is that it appears that sorted(by:) exists on the Set and Array level,

https://developer.apple.com/documentation/swift/set/2296160-sorted

https://developer.apple.com/documentation/swift/array/2296815-sorted

and isn't declared in any of the protocols that both of them conform to.

Here is my sort method:

class func sortArray(_ array:[Bom]) -> [Bom] {  

or

class func sortArray(_ array:Set<Bom>) -> [Bom] {
    return array.sorted {
        if $0.prop1 == $1.prop1 {
            if $0.prop2 == $1.prop2 {
                if $0.prop3 == $1.prop3 {
                    return $0.prop4 ?? "" < $1.prop4 ?? ""
                } else {
                    return $0.prop3 ?? "" < $1.prop3 ?? ""
                }
            } else {
                return $0.prop2 ?? "" < $1.prop2 ?? ""
            }
        } else {
            return $0.prop1 < $1.prop1
        }
    }
}

I can copy paste this method, and change the parameter type from [BOM] to Set<Bom> everything works, but now I have a literal copy-pasted function, with the only difference being the parameter type...

am I missing something simple here?

A O
  • 5,516
  • 3
  • 33
  • 68
  • Are you familiar with the `map` function? – Jake Jun 26 '18 at 00:50
  • (Possibly a bad idea) Could you define your own `protocol` which defines the function signature and then provide an extension for both `Array` and `Set` to conform to it? Might need some thinking about the conformance of the `Element` type (just thinking out load) – MadProgrammer Jun 26 '18 at 00:51
  • Jake, ye, but i'm not sure if that's what i'm looking for? MadProgrammer, that would work right, but I was mostly hoping that there was already some shared interface between set and array I could use. Worst case I'll probably go that route, because I really don't want these two methods which have literally the same exact bodies haha – A O Jun 26 '18 at 00:57
  • Ooof, you've got quite a pyramid of doom building up, it's quite a mess (look at how far `if $0.prop1 == $1.prop1` is, from its matching counterpart `return $0.prop1 < $1.prop1`. Take a look at [this answer](https://stackoverflow.com/a/37604010/3141234) to see how you can use guard statements and early returns to clear this up :) – Alexander Jun 26 '18 at 04:21

1 Answers1

2

sorted(by:) exists on all Sequences. Your specific case requires Bom, so you'd need to constrain to that:

class func sortValues<S: Sequence>(_ values: S) -> [S.Element] where S.Element == Bom {
    // .. the rest of your method
}

You could also constrain to Collection.

You can also make this an extension on Sequence or Collection of Bom:

extension Sequence where Element == Bom {
    func sorted() -> [Bom] {
        return self.sorted {
            // .. the rest of your method
        }
    }
}

If this is how Boms should always be ordered, you may also consider just making them Comparable, and then all the regular sort methods will work on all sequences:

extension Bom: Comparable {
    static func < (lhs: Bom, rhs: Bom) -> Bool {
        if lhs.prop1 == rhs.prop1 {
            if lhs.prop2 == rhs.prop2 {
                if lhs.prop3 == rhs.prop3 {
                    return lhs.prop4 ?? "" < rhs.prop4 ?? ""
                } else {
                    return lhs.prop3 ?? "" < rhs.prop3 ?? ""
                }
            } else {
                return lhs.prop2 ?? "" < rhs.prop2 ?? ""
            }
        } else {
            return lhs.prop1 < rhs.prop1
        }
    }
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    awesome, works like a charm, thank you! Yeah there are going to be multiple ways to sort, depending on user preference, so I knew this was going to get out of hand fast if I didn't find a better solution – A O Jun 26 '18 at 01:25
  • i really like the `Comparable` solution, I'm thinking of referencing a UserDefault to determine how to sort, hmm... – A O Jun 26 '18 at 01:26
  • 1
    Don't do that. Comparable should be stable; it should only be used when there is exactly one reasonable way to sort an item in your program. If you need configurability, create different `areInIncreasingOrder` functions and pass them to `sorted(by:)`. – Rob Napier Jun 26 '18 at 13:04