Skip to content

Instantly share code, notes, and snippets.

@AvdLee
Last active August 1, 2023 19:30
Show Gist options
  • Save AvdLee/0ff618b7d149be631050994ee8246bff to your computer and use it in GitHub Desktop.
Save AvdLee/0ff618b7d149be631050994ee8246bff to your computer and use it in GitHub Desktop.
KeyTimeValues Coding Challenge
let keyTimeValues: [TimeInterval: Float] = [
0.4: 0.0,
0.45: 1.0,
0.475: 1.0,
0.5: 1.0,
0.525: 1.0,
0.55: 0.0,
0.575: 1.0,
0.6: 1.0,
0.65: 1.0,
0.7: 0.0
]
/// The challenge:
/// The keys represent animation key times, the values represent values. Some key times repeat the same value of the previous keytime.
/// How would you reduce the above dictionary in such way that the values do not repeat themselves
/// more than once?
/// For example, this group:
/// 0.45: 1.0,
/// 0.475: 1.0,
/// 0.5: 1.0,
/// 0.525: 1.0,
///
/// The keytime 0.475 and 0.5 don't change the value and are, therefore, redundant in key frame animations.
///
/// Expected outcome:
let expectedOutcome: [TimeInterval: Float] = [
0.4: 0.0,
0.45: 1.0,
0.525: 1.0,
0.55: 0.0,
0.575: 1.0,
0.65: 1.0,
0.7: 0.0
]
@timvermeulen
Copy link

timvermeulen commented Jul 22, 2023

Golfed using Swift Algorithms:

import Algorithms

let keyTimeValues: [(TimeInterval, Float)] = [...]

let reduced = keyTimeValues.chunked(on: \.1).flatMap { _, chunk in
    [chunk.first, chunk.dropFirst().last].compacted()
}

(Convert to/from a dictionary as needed, but I think that was probably the incorrect choice of data structure to begin with)

@AvdLee
Copy link
Author

AvdLee commented Jul 22, 2023

Great solutions, all! Thanks a lot for joining the challenge. It's been an experiment for me and looking at the number of solutions submitted, it's definitely worth another challenge in the future.

Next time I'll make sure to provide an actual project together with a suite of tests that should succeed. Stay tuned!

@simonberner
Copy link

simonberner commented Jul 30, 2023

Great stuff @AvdLee ! Even if it takes me ages to solve such challenges, keep those coming 🙂

Here is what I came up with:

/// Reduce repeating values if they occur more than once in a dictionary.
/// - Parameter keyTimeValues: A dictionary of key-time-value pairs.
/// - Returns: A reduced dictionary.
func reduceRepeatingValues(_ keyTimeValues: [TimeInterval : Float]) -> Dictionary<TimeInterval, Float> {
    var result: [TimeInterval : Float] = [:]
    var previousValue: Float?
    var previousKey: TimeInterval?

    for key in keyTimeValues.keys.sorted() {
        let currentValue = keyTimeValues[key]

        // If the previous value has not changed, cache the current key as previousKey and continue with the next key in the loop
        if previousValue == currentValue {
            previousKey = key
            continue
        }

        // Value has changed: unwrap (because these vars are defined as optional) and add the previous key/value pair to the result
        if let pKey = previousKey, let pValue = previousValue {
            result[pKey] = pValue
        }

        // Store the current key/value pair to the result
        result[key] = currentValue

        // Cache the current key/value pair as the new previous pair
        previousKey = key
        previousValue = currentValue
    }
    return result
}

var result = reduceRepeatingValues(keyTimeValues)
assert(result == expectedOutcome, "Oh no, I failed!")

@AvdLee
Copy link
Author

AvdLee commented Jul 31, 2023

Well done @simonberner 💪🏼

@Loradim
Copy link

Loradim commented Jul 31, 2023

I guess I'm struggling with the example or explanation

let keyTimeValues: [TimeInterval: Float] = [
    0.4: 0.0,
    0.45: 1.0,
    0.475: 1.0,
    0.5: 1.0,
    0.525: 1.0,
    0.55: 0.0,
    0.575: 1.0,
    0.6: 1.0,
    0.65: 1.0,
    0.7: 0.0
]

/// Expected outcome:
let expectedOutcome: [TimeInterval: Float] = [
    0.4: 0.0,
    0.45: 1.0,
    0.525: 1.0,
    0.55: 0.0,
    0.575: 1.0,
    0.65: 1.0,
    0.7: 0.0
]

Why does 0.475 and 0.5 get removed but not 0.525? It's still repeating a value of 1.0.

I guess I'm missing out on something, would you mind pointing me towards that?

@KieranConlon
Copy link

If you have a repeating value, then keep the first and last instance of that value.
Not sure if this colour-coded version helps; essentially remove the values within the red boxes.
image

@Loradim
Copy link

Loradim commented Jul 31, 2023

@KieranConlon : Thank you !!

@MasoudRoosta
Copy link

MasoudRoosta commented Aug 1, 2023

@AvdLee It's my solution:

let keyTimeValues: [TimeInterval: Float] = [
0.4: 0.0,
0.45: 1.0,
0.475: 1.0,
0.5: 1.0,
0.525: 1.0,
0.55: 0.0,
0.575: 1.0,
0.6: 1.0,
0.65: 1.0,
0.7: 0.0
]

extension Dictionary<TimeInterval, Float>{
    func optmizedDict() -> Dictionary<TimeInterval, Float>{
        var tempElement: Dictionary<TimeInterval, Float>.Element? = nil
        return reduce([:]) { partialResult, element in
            var partialResult = partialResult
            if element.value != tempElement?.value && tempElement != nil {
                partialResult[tempElement!.key] = tempElement!.value
                partialResult[element.key] = element.value
            }
        
            tempElement = element
            return partialResult
        }
    }
}


let result = keyTimeValues.optmizedDict().sorted{$0.0 < $1.0}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment