user5398846
user5398846

Reputation:

Identifying range overlap

I have a dictionary of dictionaries that describe a person's name and date of birth and date of death.

var people = [ "Michael": [ "birth": 1900, "death" : 1975 ], "John": [ "birth": 1973, "death" : 2000 ], "Julian": [ "birth": 1950, "death" : 1985 ] ]

I would like to determine what years all members were simultaneously alive.

Here is my rather brute and unscalable implementation:

var years = [Int]()
var overlap = [Int]()    
var overlapTwice = [Int]()
var overlapThree = [Int]()

for life in people.values {
    var birth = Int(life["birth"]!)
    var death = Int(life["death"]!)

    for year in birth..<death {
        if !years.contains(year) {
            years.append(year)
        } else {
            overlap.append(year)
        }
    }
}

for x in overlap {
    if !overlapTwice.contains(x) {
        overlapTwice.append(x)
    } else {
        overlapThree.append(x)
    }
}
print(overlapThree)

I would like to know the right way to solve this problem, as mine would obviously require writing a loop for every additional range

Upvotes: 2

Views: 1259

Answers (2)

Kametrixom
Kametrixom

Reputation: 14973

As @rmaddy already mentioned, you can just get the range from the maximum birth year to the minimum death year. I suggest however to change your data structure, as it's not safe and typos can happen:

typealias Person = (name : String, lifeRange : Range<Int>)

let people : [Person] = [
    ("Michael", 1900..<1973),
    ("John", 1973..<2000),
    ("Julian", 1950..<1985)
]

func commonYearRange(people: [Person]) -> Range<Int>? {
    guard let
        minYear = people.map({ $0.lifeRange.startIndex }).maxElement(),
        maxYear = people.map({ $0.lifeRange.endIndex }).minElement()
    where minYear <= maxYear else { return nil }

    return minYear..<maxYear
}

commonYearRange(people)     // 1973..<1975

Upvotes: 1

rmaddy
rmaddy

Reputation: 318814

There's a much simpler way to solve this. Do a single loop. Keep track of the maximum birth year and the minimum death year. That will be your range.

If max birth ends up greater than min death then there is no overlap.

The following is written mostly as pseudo-code since I am not fluent in Swift:

var maxBirth = 0 // start with small value
bar minDeath = 9999 // start with large value
for life in people.values {
    var birth = Int(life["birth"]!)
    var death = Int(life["death"]!)

    if birth > maxBirth {
        maxBirth = birth
    }
    if death < minDeath {
        minDeath = death
    }
}

Your overlap range will be from maxBirth to minDeath.

Upvotes: 3

Related Questions