Improved the overall implementation of the FilterWordsUseCase use case in the Filter library.
This commit is contained in:
parent
2e52732300
commit
b01ec5ec67
@ -1,18 +1,19 @@
|
||||
//
|
||||
// FilterWordsUseCase.swift
|
||||
// ReviewsParserKit
|
||||
// ReviewsFilterKit
|
||||
//
|
||||
// Created by Javier Cicchelli on 17/03/2024.
|
||||
// Copyright © 2024 Röck+Cöde VoF. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ReviewsFoundationKit
|
||||
|
||||
public struct FilterWordsUseCase {
|
||||
|
||||
// MARK: Type aliases
|
||||
public typealias Input = String
|
||||
public typealias Output = [Tuple]
|
||||
public typealias Output = [WordCount]
|
||||
|
||||
// MARK: Initialisers
|
||||
public init() {}
|
||||
@ -32,42 +33,50 @@ public struct FilterWordsUseCase {
|
||||
|
||||
guard !matches.isEmpty else { return [] }
|
||||
|
||||
let wordsAll = matches.compactMap {
|
||||
let terms = matches.compactMap {
|
||||
Range($0.range, in: input).map { String(input[$0]) }
|
||||
}
|
||||
|
||||
let wordsAll = terms
|
||||
.map { ($0, $0.folding(options: .caseInsensitive, locale: nil)) }
|
||||
.map(Word.init)
|
||||
|
||||
let wordsCount = wordsAll.map { word -> WordCount in
|
||||
.init(
|
||||
word: word,
|
||||
count: terms.filter { $0 == word.term }.count
|
||||
)
|
||||
}.reduce(into: [WordCount]()) { partialResult, wordCount in
|
||||
guard partialResult.filter({ $0 == wordCount }).isEmpty else { return }
|
||||
|
||||
partialResult.append(wordCount)
|
||||
}
|
||||
|
||||
let wordsUnique = wordsAll
|
||||
.reduce(into: [String]()) { partialResult, word in
|
||||
guard partialResult
|
||||
.filter({ compareWords(word, $0) })
|
||||
.isEmpty
|
||||
else { return }
|
||||
|
||||
partialResult.append(
|
||||
word.folding(
|
||||
options: [
|
||||
.caseInsensitive,
|
||||
.diacriticInsensitive
|
||||
],
|
||||
locale: .current
|
||||
)
|
||||
.capitalized
|
||||
)
|
||||
}
|
||||
|
||||
return Dictionary(grouping: wordsUnique) { word in
|
||||
let wordsUnique = Dictionary(grouping: wordsCount) { wordCount -> String in
|
||||
wordsAll
|
||||
.filter { compareWords(word, $0) }
|
||||
.count
|
||||
.filter { $0.token == wordCount.word.token }
|
||||
.map(\.token)
|
||||
.first ?? .empty
|
||||
}.map { (key, values) -> WordCount in
|
||||
.init(
|
||||
word: .init(
|
||||
term: key.capitalized,
|
||||
token: key
|
||||
),
|
||||
count: values
|
||||
.map(\.count)
|
||||
.reduce(0, +)
|
||||
)
|
||||
}
|
||||
.flatMap { (key, values) -> Output in
|
||||
values.map {
|
||||
.init(word: $0, count: key)
|
||||
}
|
||||
}
|
||||
.sorted {
|
||||
|
||||
print("WORD TERMS: \(terms)")
|
||||
print("WORD ALL: \(wordsAll)")
|
||||
print("WORD COUNT: \(wordsCount)")
|
||||
print("WORD UNIQUE: \(wordsUnique)")
|
||||
|
||||
return wordsUnique.sorted {
|
||||
guard $0.count != $1.count else {
|
||||
return $0.word < $1.word
|
||||
return $0.word.token < $1.word.token
|
||||
}
|
||||
|
||||
return $0.count > $1.count
|
||||
@ -92,26 +101,6 @@ private extension FilterWordsUseCase {
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Structs
|
||||
extension FilterWordsUseCase {
|
||||
public struct Tuple: Equatable {
|
||||
|
||||
// MARK: Constants
|
||||
let word: String
|
||||
let count: Int
|
||||
|
||||
// MARK: Initialisers
|
||||
public init(
|
||||
word: String,
|
||||
count: Int
|
||||
) {
|
||||
self.word = word
|
||||
self.count = count
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - String+Constants
|
||||
private extension String {
|
||||
enum Pattern {
|
||||
|
@ -33,12 +33,12 @@ final class FilterWordsUseCaseTests: XCTestCase {
|
||||
// THEN
|
||||
XCTAssertFalse(output.isEmpty)
|
||||
XCTAssertEqual(output, [
|
||||
.init(word: "Eight", count: 1),
|
||||
.init(word: "Five", count: 1),
|
||||
.init(word: "Four", count: 1),
|
||||
.init(word: "Nine", count: 1),
|
||||
.init(word: "Seven", count: 1),
|
||||
.init(word: "Three", count: 1),
|
||||
.init(word: .init(term: "Eight", token: "eight"), count: 1),
|
||||
.init(word: .init(term: "Five", token: "five"), count: 1),
|
||||
.init(word: .init(term: "Four", token: "four"), count: 1),
|
||||
.init(word: .init(term: "Nine", token: "nine"), count: 1),
|
||||
.init(word: .init(term: "Seven", token: "seven"), count: 1),
|
||||
.init(word: .init(term: "Three", token: "three"), count: 1),
|
||||
])
|
||||
}
|
||||
|
||||
@ -52,18 +52,18 @@ final class FilterWordsUseCaseTests: XCTestCase {
|
||||
// THEN
|
||||
XCTAssertFalse(output.isEmpty)
|
||||
XCTAssertEqual(output, [
|
||||
.init(word: "Five", count: 2),
|
||||
.init(word: "Nine", count: 2),
|
||||
.init(word: "Three", count: 2),
|
||||
.init(word: "Eight", count: 1),
|
||||
.init(word: "Four", count: 1),
|
||||
.init(word: "Seven", count: 1),
|
||||
.init(word: .init(term: "Five", token: "five"), count: 2),
|
||||
.init(word: .init(term: "Nine", token: "nine"), count: 2),
|
||||
.init(word: .init(term: "Three", token: "three"), count: 2),
|
||||
.init(word: .init(term: "Eight", token: "eight"), count: 1),
|
||||
.init(word: .init(term: "Four", token: "four"), count: 1),
|
||||
.init(word: .init(term: "Seven", token: "seven"), count: 1),
|
||||
])
|
||||
}
|
||||
|
||||
func testCallAsFunction_withInput_hasSomeRepeatedCaseSensitiveLongWords() throws {
|
||||
// GIVEN
|
||||
input = "one two three Three four Five five six seven eight nine nine ten"
|
||||
input = "one two three ThReE four FIVE five six seven eight NiNe nInE ten"
|
||||
|
||||
// WHEN
|
||||
output = try sut(input)
|
||||
@ -71,18 +71,18 @@ final class FilterWordsUseCaseTests: XCTestCase {
|
||||
// THEN
|
||||
XCTAssertFalse(output.isEmpty)
|
||||
XCTAssertEqual(output, [
|
||||
.init(word: "Five", count: 2),
|
||||
.init(word: "Nine", count: 2),
|
||||
.init(word: "Three", count: 2),
|
||||
.init(word: "Eight", count: 1),
|
||||
.init(word: "Four", count: 1),
|
||||
.init(word: "Seven", count: 1),
|
||||
.init(word: .init(term: "Five", token: "five"), count: 2),
|
||||
.init(word: .init(term: "Nine", token: "nine"), count: 2),
|
||||
.init(word: .init(term: "Three", token: "three"), count: 2),
|
||||
.init(word: .init(term: "Eight", token: "eight"), count: 1),
|
||||
.init(word: .init(term: "Four", token: "four"), count: 1),
|
||||
.init(word: .init(term: "Seven", token: "seven"), count: 1),
|
||||
])
|
||||
}
|
||||
|
||||
func testCallAsFunction_withInput_hasSomeRepeatedDiacriticSensitiveLongWords() throws {
|
||||
func testCallAsFunction_withInput_hasSomeDiacriticSensitiveLongWords() throws {
|
||||
// GIVEN
|
||||
input = "one two thrèé Three four Fíve fïve six Šëvêń seven eight niñe nine ten"
|
||||
input = "one two three Thrèé four FiVe FIVE six Šëvêń seven eight niñe nine ten"
|
||||
|
||||
// WHEN
|
||||
output = try sut(input)
|
||||
@ -90,12 +90,15 @@ final class FilterWordsUseCaseTests: XCTestCase {
|
||||
// THEN
|
||||
XCTAssertFalse(output.isEmpty)
|
||||
XCTAssertEqual(output, [
|
||||
.init(word: "Five", count: 2),
|
||||
.init(word: "Nine", count: 2),
|
||||
.init(word: "Seven", count: 2),
|
||||
.init(word: "Three", count: 2),
|
||||
.init(word: "Eight", count: 1),
|
||||
.init(word: "Four", count: 1),
|
||||
.init(word: .init(term: "Five", token: "five"), count: 2),
|
||||
.init(word: .init(term: "Eight", token: "eight"), count: 1),
|
||||
.init(word: .init(term: "Four", token: "four"), count: 1),
|
||||
.init(word: .init(term: "Nine", token: "nine"), count: 1),
|
||||
.init(word: .init(term: "Niñe", token: "niñe"), count: 1),
|
||||
.init(word: .init(term: "Seven", token: "seven"), count: 1),
|
||||
.init(word: .init(term: "Three", token: "three"), count: 1),
|
||||
.init(word: .init(term: "Thrèé", token: "thrèé"), count: 1),
|
||||
.init(word: .init(term: "Šëvêń", token: "šëvêń"), count: 1),
|
||||
])
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user