#ios #arrays #swift #xcode
Вопрос:
Я хотел бы взять массив [String]
и разделить его на заданное количество групп.
Я пробовал использовать это расширение
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to:count, by: size).map {
Array(self[$0 ..< Swift.min($0 size, count)])
}
}
}
чтобы разделить массив на заданное количество элементов в подмассиве, которое для этой функции работает.
Но чтобы разделить его на желаемое количество подмножеств, я попытался разделить array.count
его на желаемое количество команд, что работает, но только при определенных обстоятельствах.
Если есть какие-либо дополнительные элементы, это помещает их в дополнительный подмассив в конце, и число должно получиться, даже если я хочу, чтобы это работало идеально, что в большинстве случаев является меньшинством.
Поэтому я думаю, что эта array.chunked
функция никоим образом не является решением.
Возможно , есть способ сделать это с помощью цикла for, взяв array.randomElement()
, добавив его в переменную (которая будет командой), а затем удалив этот элемент из исходного массива и повторяя его до тех пор, пока исходный массив не опустеет. И в итоге получим массив подмассивов, которые будут командами, или просто отдельные переменные, которые будут командами. Это может быть любой из этих вариантов.
Есть какие-нибудь идеи о том, как это сделать?
Комментарии:
1. Не существует стратегии выбора, которая позволила бы вам разделить нечетное количество людей на две команды одинакового размера. Это просто невозможно. Самое близкое, что вы, вероятно, можете сделать,-это взять «остатки» (последний возвращенный подмассив
Array.chunked(into:)
) и распределить этих игроков между существующими командами, чтобы размер команды отличался не более чем на 12. @Alexander Да, именно об этом я и думал. Проблема в том, что иногда более 1 массива в конечном итоге становятся дополнительными, и функция Array.chunked(into:) просто устанавливает ограничение на количество элементов в массиве.
3. Вы хотите выбрать членов команды случайным образом?
4. @DuncanC Да, но я могу просто передать массив как .shuffled().
Ответ №1:
Подумайте о том, как вы сдаете карты.
Если у вас 7 игроков, вы начинаете с одного игрока и ходите по кругу, раздавая каждому игроку по одной карте за раз. В конце концов, у вас могут закончиться карты, прежде чем вы дадите всем одинаковое количество карт. У некоторых людей может быть n карт, а у некоторых может быть n-1. Это лучшее, что ты можешь сделать.
Вы могли бы реализовать то же самое с исходным массивом и целевыми массивами. Удаляйте по одному элементу за раз из исходного массива и «обходным путем» добавляйте его в один из целевых массивов до тех пор, пока исходный массив не будет исчерпан.
Этот код может выглядеть следующим образом:
func splitArray<T>(array: [T], subArrayCount: Int) -> [[T]] {
// Create an empty array of arrays
var result = [[T]]()
// Create the empty inner string arrays
for _ in 1...subArrayCount {
let innerArray = [T]()
result.append(innerArray)
}
for (index, element) in array.enumerated() {
result[index % subArrayCount].append(element)
}
return result
}
И чтобы проверить это:
let string = "Now is the time for all good programmers to babble incoherently. The rain in spain falls mainly on the plain. Fourscore and seven years ago our forefathers brought forth to this continent a new nation conceived in liberty and dedicated to the cause that all men are created equal."
let array = string.split(separator: " ")
.map { String($0) }
let subArrays: [[String]] = splitArray(array: array, subArrayCount: 5)
for (index, array) in subArrays.enumerated() {
let countString = String(format: "-", array.count)
print ("Array[(index)]. Count = (countString). Contents = (array)")
}
Результатом этого теста является:
Array[0]. Count = 10. Contents = ["Now", "all", "incoherently.", "falls", "Fourscore", "our", "this", "conceived", "to", "men"]
Array[1]. Count = 10. Contents = ["is", "good", "The", "mainly", "and", "forefathers", "continent", "in", "the", "are"]
Array[2]. Count = 10. Contents = ["the", "programmers", "rain", "on", "seven", "brought", "a", "liberty", "cause", "created"]
Array[3]. Count = 10. Contents = ["time", "to", "in", "the", "years", "forth", "new", "and", "that", "equal."]
Array[4]. Count = 9. Contents = ["for", "babble", "spain", "plain.", "ago", "to", "nation", "dedicated", "all"]
Комментарии:
1. Итак, я должен сделать цикл for, чтобы непрерывно добавлять элемент из исходного массива в другие массивы? Как мне указать циклу for, в какой массив он должен добавить элемент? Или есть лучший способ сделать это?
2. Я получаю ошибку в объявлении второго цикла for, в котором говорится: «Шаблон кортежа не может соответствовать значениям типа»Строка», не относящегося к кортежу»». Как я могу это исправить?
3. Ага. Я должен знать лучше, чем набирать код в редакторе SO. Я обновил свой ответ.
4. Я переработал функцию, чтобы использовать универсальные, поэтому она будет разделять массивы любого типа.