I've an array as
[1,5,3,3,4,4,4,5,6,6,6,6,8,9,1,1,5]
Here, '4' is continuously repeating 3 times and '6' is repeating 4 times. Array length is not fixed.
So I need to iterate this array to find the max number repeating continuously. So, 4 and 6 both are repeating but the highest is 6 so the function should return 6 and its starting index and ending index in short time.
I've a Case 2 as well.
[10,11,10,10,11,10,15,16,20,21,22,21,21,20,20]
In the above case, the slight difference between values can be negligible. For eg.
first sequence has 10,11,10,10,11,10
and second sequence has 20,21,22,21,21,20,20
and the highest repetitive values will be second sequence
If tolerance is 1 then first case will be considered instead second sequence. Because if tolerance is 1 then the second sequence would be [21,21,20,20]
, hence maximum number(count) of occurrences is in first case.
Any help would be appreciated.
I made a reduce map for finding the max occurring result, I've added a enumerated map to the Int array for getting the value its index inside the reduce map, all code is tested with Swift 4.
Sorting method:
let array: [(Int, Int)] = [1, 5, 3, 3, 4, 4, 4, 5, 6, 6, 6, 6, 8, 9, 1, 1, 5].enumerated().map { ($0, $1) }
var results: [Result] = []
guard let maxResult = array.reduce(nil, { (maxResult, item) -> Result? in
let (index, value) = item
guard let result = results.first(where: { (result) -> Bool in
result.value == value && result.endIndex + 1 == index
}) else {
let result = Result(value, startIndex: index)
results.append(result)
return result > maxResult ? result : maxResult
}
result.endIndex = index
return result > maxResult ? result : maxResult
}) else {
print("no max result found :(")
return
}
print("found max result: \(maxResult) in results: \(results)")
Result class:
class Result {
let value: Int
var numberOfOcurrences: Int
let startIndex: Int
var endIndex: Int {
didSet {
numberOfOcurrences += 1
}
}
init(_ value: Int, startIndex: Int) {
self.value = value
self.startIndex = startIndex
self.endIndex = startIndex
self.numberOfOcurrences = 1
}
static func > (lhs: Result, rhs: Result?) -> Bool {
return lhs.numberOfOcurrences > rhs?.numberOfOcurrences ?? 0
}
}
extension Result: CustomStringConvertible {
var description: String {
return """
Result(
value: \(value),
numberOfOcurrences: \(numberOfOcurrences),
startIndex: \(startIndex),
endIndex: \(endIndex)
)
"""
}
}
Output:
/* output: found max result: Result(
value: 6,
numberOfOcurrences: 4,
startIndex: 8,
endIndex: 11
) in results: [
Result(
value: 1,
numberOfOcurrences: 1,
startIndex: 0,
endIndex: 0
),
Result(
value: 5,
numberOfOcurrences: 1,
startIndex: 1,
endIndex: 1
),
Result(
value: 3,
numberOfOcurrences: 2,
startIndex: 2,
endIndex: 3
),
Result(
value: 4,
numberOfOcurrences: 3,
startIndex: 4,
endIndex: 6
),
Result(
value: 5,
numberOfOcurrences: 1,
startIndex: 7,
endIndex: 7
),
Result(
value: 6,
numberOfOcurrences: 4,
startIndex: 8,
endIndex: 11
),
Result(
value: 8,
numberOfOcurrences: 1,
startIndex: 12,
endIndex: 12
),
Result(
value: 9,
numberOfOcurrences: 1,
startIndex: 13,
endIndex: 13
),
Result(
value: 1,
numberOfOcurrences: 2,
startIndex: 14,
endIndex: 15
),
Result(
value: 5,
numberOfOcurrences: 1,
startIndex: 16,
endIndex: 16
)
]
*/
UPDATE: for case 2
let array: [(Int, Int)] = [10, 11, 10, 10, 11, 10, 15, 16, 20, 21, 22, 21, 21, 20, 20].enumerated().map { ($0, $1) }
var results: [Result] = []
let tolerance: Int = 1 // now there can be one other in between
guard let maxResult = array.reduce(nil, { (maxResult, item) -> Result? in
let (index, value) = item
guard let result = results.first(where: { (result) -> Bool in
return result.value == value && result.endIndex + (1 + tolerance) >= index
}) else {
let result = Result(value, startIndex: index)
results.append(result)
return result > maxResult ? result : maxResult
}
result.endIndex = index
return result > maxResult ? result : maxResult
}) else {
print("no max result found :(")
return
}
print("found max result: \(maxResult) in results: \(results)")
Output:
/* output: found max result: Result(
value: 10,
numberOfOcurrences: 4,
startIndex: 0,
endIndex: 5
) in results: [
Result(
value: 10,
numberOfOcurrences: 4,
startIndex: 0,
endIndex: 5
), Result(
value: 11,
numberOfOcurrences: 1,
startIndex: 1,
endIndex: 1
), Result(
value: 11,
numberOfOcurrences: 1,
startIndex: 4,
endIndex: 4
), Result(
value: 15,
numberOfOcurrences: 1,
startIndex: 6,
endIndex: 6
), Result(
value: 16,
numberOfOcurrences: 1,
startIndex: 7,
endIndex: 7
), Result(
value: 20,
numberOfOcurrences: 1,
startIndex: 8,
endIndex: 8
), Result(
value: 21,
numberOfOcurrences: 3,
startIndex: 9,
endIndex: 12
), Result(
value: 22,
numberOfOcurrences: 1,
startIndex: 10,
endIndex: 10
), Result(
value: 20,
numberOfOcurrences: 2,
startIndex: 13,
endIndex: 14
)
]
*/
UPDATE 3: edited Result class to store number of values in sequence
class Result {
let value: Int
var numberOfOcurrences: Int
var numberOfValuesInSequence: Int
let startIndex: Int
var endIndex: Int {
didSet {
numberOfOcurrences += 1
numberOfValuesInSequence = (endIndex - startIndex) + 1
}
}
init(_ value: Int, startIndex: Int) {
self.value = value
self.startIndex = startIndex
self.endIndex = startIndex
self.numberOfOcurrences = 1
self.numberOfValuesInSequence = 1
}
static func > (lhs: Result, rhs: Result?) -> Bool {
return lhs.numberOfValuesInSequence > rhs?.numberOfValuesInSequence ?? 0
}
}
extension Result: CustomStringConvertible {
var description: String {
return """
Result(
value: \(value),
numberOfOcurrences: \(numberOfOcurrences),
numberOfValuesInSequence: \(numberOfValuesInSequence),
startIndex: \(startIndex),
endIndex: \(endIndex)
)
"""
}
}
Output:
Result(
value: 10,
numberOfOcurrences: 4,
numberOfValuesInSequence: 6,
startIndex: 0,
endIndex: 5
)