Skip to content

Instantly share code, notes, and snippets.

@fxm90
Last active January 25, 2026 16:35
Show Gist options
  • Select an option

  • Save fxm90/3113ba447cc7275836591497a0c2ee47 to your computer and use it in GitHub Desktop.

Select an option

Save fxm90/3113ba447cc7275836591497a0c2ee47 to your computer and use it in GitHub Desktop.
Counterpart methods to `mapValues(_:)` and `compactMapValues(_:)`
//
// Dictionary+MapKeys.swift
//
// Created by Felix Mau on 14.06.21.
// Copyright © 2021 Felix Mau. All rights reserved.
//
extension Dictionary {
/// Returns a new dictionary with the keys transformed by the given closure
/// and the original values.
///
/// Use this method to transform the keys of a dictionary while keeping
/// the associated values intact. Note that if the `transform` closure
/// produces the same key for different original keys, the last key-value
/// pair processed will overwrite previous ones.
///
/// - Parameter transform: A closure that takes a key and value of the
/// dictionary as its argument and returns a
/// transformed key of type `T`.
///
/// - Returns: A dictionary containing the transformed keys and the
/// original values.
///
/// - Complexity: O(*n*), where *n* is the length of the dictionary.
func mapKeys<T: Hashable>(_ transform: (Key, Value) -> T) -> [T: Value] {
reduce(into: [T: Value]()) { result, element in
let mappedKey = transform(element.key, element.value)
result[mappedKey] = element.value
}
}
/// Returns a new dictionary containing only the non-`nil` keys produced
/// by the given transformation, paired with the original values.
///
/// Use this method to simultaneously transform and filter the keys of
/// a dictionary. If `transform` returns `nil` for a key, that key-value
/// pair is excluded from the resulting dictionary.
///
/// - Parameter transform: A closure that takes a key and value of the
/// dictionary as its argument and returns an
/// optional transformed key of type `T?`.
/// - Returns: A dictionary containing the non-`nil` transformed keys
/// and the original values.
///
/// - Complexity: O(*n*), where *n* is the length of the dictionary.
func compactMapKeys<T: Hashable>(_ transform: (Key, Value) -> T?) -> [T: Value] {
reduce(into: [T: Value]()) { result, element in
guard let mappedKey = transform(element.key, element.value) else {
return
}
result[mappedKey] = element.value
}
}
}
@fxm90
Copy link
Author

fxm90 commented Jan 25, 2026

Unit-Tests for mapKeys(_:)

import Testing

@Suite
struct DictionaryMapKeysTests {

  @Test
  func mapKeys_shouldInvokeCallback_withCorrectKey_andValue() {
    // Given
    var receivedKey: Int?
    var receivedValue: String?

    let dictionary = [
      1: "one",
    ]

    // When
    _ = dictionary.mapKeys { key, value in
      receivedKey = key
      receivedValue = value

      return key
    }

    // Then
    #expect(receivedKey == 1)
    #expect(receivedValue == "one")
  }

  @Test
  func mapKeys_shouldReturnDictionary_withMappedKeys_andOriginalValues() {
    // Given
    let dictionary = [
      1: "one",
      2: "two",
      3: "three",
    ]

    // When
    let result = dictionary.mapKeys { key, _ in
      key * 2
    }

    // Then
    let expectedDictionary = [
      2: "one",
      4: "two",
      6: "three",
    ]

    #expect(result == expectedDictionary)
  }
}

@fxm90
Copy link
Author

fxm90 commented Jan 25, 2026

Unit-Tests for compaceMapKeys(_:)

import Testing

@Suite
struct DictionaryCompactMapKeysTests {

  @Test
  func compactMapKeys_shouldInvokeCallback_withCorrectKey_andValue() {
    // Given
    var receivedKey: Int?
    var receivedValue: String?

    let dictionary = [
      1: "one",
    ]

    // When
    _ = dictionary.compactMapKeys { key, value in
      receivedKey = key
      receivedValue = value

      return key
    }

    // Then
    #expect(receivedKey == 1)
    #expect(receivedValue == "one")
  }

  @Test
  func compactMapKeys_shouldReturnDictionary_withMappedKeys_andOriginalValues() {
    // Given
    let dictionary = [
      1: "one",
      2: "two",
      3: "three",
    ]

    // When
    let result = dictionary.compactMapKeys { key, _ in
      key.isMultiple(of: 2)
        ? nil
        : key * 2
    }

    // Then
    let expectedDictionary = [
      2: "one",
      6: "three",
    ]

    #expect(result == expectedDictionary)
  }
}

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