'Change value in array in order

I need to change maximum values to order. First in order will be maximum value and maximum value - 1. (100, 99, 100) must be equal to 1. It will be [5, 55, 1, 2, 1, 1, 98]. Then I need to change (98) to 2 because now 98 is maximum value in array. My goal is to have [4, 3, 1, 5, 1, 1, 2]. I tried my first steps and received this

var arr = [5, 55, 100, 2, 99, 100, 98]

func toOrder(_ arr: [Int]) -> [Int] {
  var arr = arr
  var max = arr.max()!
  var order = 1
  for i in arr.indices { 
    if arr[i] == max || arr[i] == max - 1 { 
       arr[i] = order
    }
  
  }
 return arr
}
toOrder(arr)
  

There i'm stuck. I received [5, 55, 1, 2, 1, 1, 98], but how can i continue to iterate through array with saved values?



Solution 1:[1]

First zip the collection elements with their indices and sort by their elements in decreasing order. Create rank and maxValue vars.
Create an array with exact same number of elements for storing the result.
Iterate the elements and indices.
If the element is less than maxValue minus one increase the rank value, update the maxValue and store the rank at the corresponding position of the original element at the resulting array:

let arr =  [5, 55, 100, 2, 99, 100, 98]

let indexedElements = zip(arr.indices, arr).sorted(by: { $0.1 > $1.1 })
var rank = 1
var maxValue = indexedElements.first?.1 ?? .max
var result = Array(repeating: 0, count: arr.count)
for index in indexedElements.indices {
    let element = indexedElements[index].1
    if element < maxValue - 1 {
        rank += 1
        maxValue = element
    }
    result[indexedElements[index].0] = rank
}
print(result)  // "[4, 3, 1, 5, 1, 1, 2]\n"

Solution 2:[2]

I have no idea what you should call this.

extension Sequence
where Element: AdditiveArithmetic & Comparable & ExpressibleByIntegerLiteral & Hashable {
  var ?: [Int] {
    var dictionary: [Element: Int] = [:]

    func value(for element: Element) -> Int? {
      dictionary[element] ?? dictionary[element + 1]
    }

    _ = sorted().reversed().reduce(into: 0) { highestValue, element in
      if value(for: element) == nil {
        highestValue += 1
        dictionary[element] = highestValue
      }
    }

    return map(value) as! _
  }
}

Solution 3:[3]

If I understood correctly your logic (because you gave a sample, which answer didn't seem right, I'll talk about later):

I'd go with a recursive method.

  • Find the max "untreated" value (else, once you have for instance the final output, it will iterate over and over), and stop if not found.
  • Update the array for values are equal to the max, or equal to the max - 1.
  • Redo
 func iterates(items: inout [Item], iteration: Int = 0) {
        let maxValue = items.filter { !$0.hasBeenTreated }.max(by: { $0.value < $1.value })
        print("maxValue found: \(maxValue)")
        guard let maxValue = maxValue else { return } //Check if there are still value max non treated, else, it ends here
        let newItems = items.map { anItem -> Item in
            if anItem.hasBeenTreated == false && (anItem.value == maxValue.value || anItem.value == maxValue.value - 1) {
                return Item(value: iteration + 1, hasBeenTreated: true)
            } else {
                return anItem
            }
        }
        print("NewItems: \(newItems)")
        items = newItems
        iterates(items: &items, iteration: iteration + 1)
    }

With the help of:

struct Item: CustomStringConvertible {
    var value: Int
    var hasBeenTreated: Bool

    var description: String {
        return "\(value) (\(hasBeenTreated))"
    }
}

To test it:

var itemsToTest1 = [5, 55, 100, 2, 99, 100, 98].map { Item(value: $0, hasBeenTreated: false) }
iterates(items: &itemsToTest1)
print("Output Items1: \(itemsToTest1)")
print("Output Array1: \(itemsToTest1.map({ $0.value }))")

var itemsToTest2 = [1, 2, 3, 4, 5, 6, 7, 8, 9].map { Item(value: $0, hasBeenTreated: false) }
iterates(items: &itemsToTest2)
print("Output Items2: \(itemsToTest2)")
print("Output Array2: \(itemsToTest2.map({ $0.value }))")

The outputs are just for debugging, but you can see the advancement of the calculations:

maxValue found: Optional(100 (false))
NewItems: [5 (false), 55 (false), 1 (true), 2 (false), 1 (true), 1 (true), 98 (false)]
maxValue found: Optional(98 (false))
NewItems: [5 (false), 55 (false), 1 (true), 2 (false), 1 (true), 1 (true), 2 (true)]
maxValue found: Optional(55 (false))
NewItems: [5 (false), 3 (true), 1 (true), 2 (false), 1 (true), 1 (true), 2 (true)]
maxValue found: Optional(5 (false))
NewItems: [4 (true), 3 (true), 1 (true), 2 (false), 1 (true), 1 (true), 2 (true)]
maxValue found: Optional(2 (false))
NewItems: [4 (true), 3 (true), 1 (true), 5 (true), 1 (true), 1 (true), 2 (true)]
maxValue found: nil
Output Items1: [4 (true), 3 (true), 1 (true), 5 (true), 1 (true), 1 (true), 2 (true)]
Output Array1: [4, 3, 1, 5, 1, 1, 2]
maxValue found: Optional(9 (false))
NewItems: [1 (false), 2 (false), 3 (false), 4 (false), 5 (false), 6 (false), 7 (false), 1 (true), 1 (true)]
maxValue found: Optional(7 (false))
NewItems: [1 (false), 2 (false), 3 (false), 4 (false), 5 (false), 2 (true), 2 (true), 1 (true), 1 (true)]
maxValue found: Optional(5 (false))
NewItems: [1 (false), 2 (false), 3 (false), 3 (true), 3 (true), 2 (true), 2 (true), 1 (true), 1 (true)]
maxValue found: Optional(3 (false))
NewItems: [1 (false), 4 (true), 4 (true), 3 (true), 3 (true), 2 (true), 2 (true), 1 (true), 1 (true)]
maxValue found: Optional(1 (false))
NewItems: [5 (true), 4 (true), 4 (true), 3 (true), 3 (true), 2 (true), 2 (true), 1 (true), 1 (true)]
maxValue found: nil
Output Items2: [5 (true), 4 (true), 4 (true), 3 (true), 3 (true), 2 (true), 2 (true), 1 (true), 1 (true)]
Output Array2: [5, 4, 4, 3, 3, 2, 2, 1, 1]

Now, going with the last example given in a comment (deleted answer): [1, 2, 3, 4, 5, 6, 7, 8, 9] should produce `[ 5, 5, 4, 4, 3, 3, 2, 2, 1, 1], but I disagree.

Iterations should be:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 1, 1]
[1, 2, 3, 4, 5, 2, 2, 1, 1]
[1, 2, 3, 3, 3, 2, 2, 1, 1]
[1, 4, 4, 3, 3, 2, 2, 1, 1]
[5, 4, 4, 3, 3, 2, 2, 1, 1] (with only one 5 value at start)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Larme