How to print all values in a Lua table? - arrays

If I have a table like this, how would I print all the values?
local Buyers = {
{[Name] = "Birk", [SecName] = "Birk2nd", [ThirdName] = "Birk3nd"},
{[Name] = "Bob", [SecName] = "Bob2nd", [ThirdName] = "Bob3nd"},
}
It should end up printing:
First Name: Birk
Second Name: Birk2nd
Third Name: Birk3nd
FirstName: Bob
Second Name: Bob2nd
Third Name: Bob3nd

what i can think of
local Buyers = {
{["Name"] = "Birk", ["SecName"] = "Birk2nd", ["ThirdName"] = "Birk3nd"},
{["Name"] = "Bob", ["SecName"] = "Bob2nd", ["ThirdName"] = "Bob3nd"},
}
for _, person in pairs(Buyers) do
print("First name: "..person.Name)
print("Second name: "..person.SecName)
print("Third name: "..person.ThirdName)
print()
end

For your case, like this:
local function serialise_buyer (buyer)
return ('First Name: ' .. (buyer.Name or '')) .. '\n'
.. ('Second Name: ' .. (buyer.SecName or '')) .. '\n'
.. ('Third Name: ' .. (buyer.ThirdName or '')) .. '\n'
end
local Buyers = {
{Name = "Birk", SecName = "Birk2nd", ThirdName = "Birk3rd"},
{Name = "Bob", SecName = "Bob2nd", ThirdName = "Bob3rd"},
}
for _, buyer in ipairs (Buyers) do
print (serialise_buyer (buyer))
end
A more generic solution, with sorting:
local sort, rep, concat = table.sort, string.rep, table.concat
local function serialise (var, sorted, indent)
if type (var) == 'string' then
return "'" .. var .. "'"
elseif type (var) == 'table' then
local keys = {}
for key, _ in pairs (var) do
keys[#keys + 1] = key
end
if sorted then
sort (keys, function (a, b)
if type (a) == type (b) and (type (a) == 'number' or type (a) == 'string') then
return a < b
elseif type (a) == 'number' and type (b) ~= 'number' then
return true
else
return false
end
end)
end
local strings = {}
local indent = indent or 0
for _, key in ipairs (keys) do
strings [#strings + 1]
= rep ('\t', indent + 1)
.. serialise (key, sorted, indent + 1)
.. ' = '
.. serialise (var [key], sorted, indent + 1)
end
return 'table (\n' .. concat (strings, '\n') .. '\n' .. rep ('\t', indent) .. ')'
else
return tostring (var)
end
end
local Buyers = {
{Name = "Birk", SecName = "Birk2nd", ThirdName = "Birk3rd"},
{Name = "Bob", SecName = "Bob2nd", ThirdName = "Bob3rd"},
[function () end] = 'func',
[{'b', 'd'}] = {'e', 'f'}
}
print (serialise (Buyers, true))

Related

Swift split array into chunks based on total value

I am looking for a way to split an array into chunks with a max value, but can't seem to find a solution.
Lets say we have the following code:
struct FooBar {
let value: Int
}
let array: [FooBar] = [
FooBar(value: 1),
FooBar(value: 2),
FooBar(value: 1),
FooBar(value: 1),
FooBar(value: 1),
FooBar(value: 2),
FooBar(value: 2),
FooBar(value: 1)
]
And we want to split this into chunks where the maxSize of FooBar.value doesn't exceed 3. The end result should be something like:
let ExpectedEndResult: [[FooBar]] = [
[
FooBar(value: 1),
FooBar(value: 2)
],
[
FooBar(value: 1),
FooBar(value: 1),
FooBar(value: 1)
],
[
FooBar(value: 2),
],
[
FooBar(value: 2),
FooBar(value: 1)
]
]
I've written this so far, but there is an issue when a 3rd item could be added, also... I believe there must be simpler way but I just can't think of one right now:
extension Array where Element == FooBar {
func chunked(maxValue: Int) -> [[FooBar]] {
var chunks: [[FooBar]] = []
var chunk: [FooBar] = []
self.enumerated().forEach { key, value in
chunk.append(value)
if self.count-1 > key {
let next = self[key+1]
if next.value + value.value > maxValue {
chunks.append(chunk)
chunk = []
}
} else {
chunks.append(chunk)
}
}
return chunks
}
}
Any suggestions?
I would use reduce(into:) for this
let maxValue = 3 //limit
var currentValue = 0 // current total value for the last sub array
var index = 0 // index of last (current) sub array
let groups = array.reduce(into: [[]]) {
if $1.value > maxValue || $1.value + currentValue > maxValue {
$0.append([$1])
currentValue = $1.value
index += 1
} else {
$0[index].append($1)
currentValue += $1.value
}
}
To make it more universal, here is a generic function as an extension to Array that also uses a KeyPath for the value to chunk over
extension Array {
func chunk<ElementValue: Numeric & Comparable>(withLimit limit: ElementValue,
using keyPath: KeyPath<Element, ElementValue>) -> [[Element]] {
var currentValue = ElementValue.zero
var index = 0
return self.reduce(into: [[]]) {
let value = $1[keyPath: keyPath]
if value > limit || value + currentValue > limit {
$0.append([$1])
currentValue = value
index += 1
} else {
$0[index].append($1)
currentValue += value
}
}
}
}
Usage for the sample
let result = array.chunk(withLimit: 3, using: \.value)
Something like:
extension Array where Element == FooBar {
func chunked(maxValue: Int) -> [[FooBar]] {
var chunks: [[FooBar]] = []
var chunk: [FooBar] = []
let filtered = self.filter({ item in
item.value <= maxValue
})
filtered.enumerated().forEach { index, foo in
let currentTotal = chunk.reduce(0, { sum, nextFoo in sum + nextFoo.value })
let newValue = currentTotal + foo.value
if newValue < maxValue {
chunk.append(foo)
} else if newValue == maxValue {
chunk.append(foo)
chunks.append(chunk)
chunk = []
} else {
chunks.append(chunk)
chunk = [foo]
}
}
return chunks
}
}
It could be interesting to write something that goes looking in the array for the perfect groups. The problem with the sequential approach is that one can end up with groups are very low in value when there are perfectly good foos that could fit in the chunk, but they just aren't the next item.
Edit: Added a filter for values above maxValue ... just in case.

Can't fill 2d-array by brackets in Kotlin despite getter and setter

It should become a little consolewalker program but I can't fill the 2d-array I created in class Field in class Player by brackets because there "are to many arguments" for set function despite there is one that should fit. Also I have learned that it isn't even necessary in Kotlin.
So I am a little bit confused and get no further.
fun main() {
val gameField = Field()
gameField.buildField()
val player = Player(gameField.field)
gameField.printField()
var input: String? = " "
while (input != "x") {
println("w: ↑ a: ← s: ↓ d: →")
input = readLine()
when (input) {
"w" -> player.counter = 0
"a" -> player.counter = 1
"s" -> player.counter = 2
"d" -> player.counter = 3
"x" -> return println("Spiel wird beendet")
" " -> player.move()
else -> println("Ungültige Eingabe")
}
player.setPlayer()
gameField.printField()
}
}
class Field() {
private var field = Array(10) {Array(10){" "}}
operator fun set(row: Int, col: Int, value: String) {
field[row][col] = value
}
operator fun get(row: Int, col: Int) = field[row][col]
fun buildField() {
for (i in field.indices) {
field[i][0] = "# "
field[i][field.size - 1] = "# "
for (j in 1 until field.size - 1) {
field[i][j] = " "
field[0][j] = "# "
field[field.size - 1][j] = "# "
}
}
}
fun printField() {
for (i in field.indices) {
for (j in field[i].indices) {
print(field[i][j])
}
println()
}
}
}
class Player(private var gameField: Array<Array<String>>) {
private val playerSign = arrayOf<String>("↑ ", "← ", "↓ ", "→ ")
var currentRow = 4
var currentColumn = 4
var counter = 0
init {
setPlayer()
}
fun setPlayer() {
gameField[currentRow, currentColumn] = playerSign[counter]
}
fun reset() {
gameField[currentRow, currentColumn] = " "
}
fun move() {
reset()
when(counter) {
0 -> if (currentRow > 1) currentRow--
1 -> if (currentColumn > 1) currentColumn--
2 -> if (currentRow < gameField.size-2) currentRow++
3 -> if (currentColumn < gameField.size-2) currentColumn++
}
setPlayer()
}
}
Thanks in advance!
Problem with your code is that in class Player field is of type Field, its not an array, that is why compiler is giving you the error. if you want to access the field array of Field class then you should do
field.field[3][3] = playerSign[counter]
You could extend you Field class with an overloaded get and set operator (see Operator Overloading | Indexed Access Operator in the language documentation).
class Field() {
// all your existing code
operator fun set(row : Int, col : Int, value : String) {
field[row][col] = value
}
operator fun get(row : Int, col : Int) = field[row][col]
}
As the documentation states:
Square brackets are translated to calls to get and set with appropriate numbers of arguments.
Thus, you now can write
field[currentRow, currentColumn] = playerSign[counter]
in your Player class which is more clean than exposing / accessing the array itself (which could and should now be made private).

Calculate the data received inside the recursive function

The function outputs via print() all possible combinations of the characters "abc". (Depending on the specified length)
I need to calculate this amount. I only managed to output these combinations one by one through print(). I left a comment in the right place of the code.
func allLexicographicRecur (_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int){
var length = string.count-1
var data = data
for i in 0...length {
data[index] = String(string[i])
if index == last {
print(data.joined()) // Displays a combination. It is necessary to somehow calculate.
}else{
allLexicographicRecur(string, data, last, index+1)
}
}
}
func allLexicographic(_ l: Int) {
var alphabet = "abc"
var data = Array(repeating: "", count: l)
var string = alphabet.sorted()
var counter = 0
allLexicographicRecur(string, data, l-1, 0)
}
allLexicographic(3)
The function must somehow return the number of these combinations.
I would be very grateful for the help!
I managed to count only this way (but most likely it is not the best way to do it):
var count = 0
func allLexicographicRecur (_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int){
var length = string.count-1
var data = data
for i in 0...length {
data[index] = String(string[i])
if index == last {
print(data.joined()) // Displays a combination. It is necessary to somehow calculate.
count += 1
}else{
allLexicographicRecur(string, data, last, index+1)
}
}
}
func allLexicographic(_ l: Int) {
var alphabet = "abc"
var data = Array(repeating: "", count: l)
var string = alphabet.sorted()
var counter = 0
allLexicographicRecur(string, data, l-1, 0)
}
allLexicographic(3)
print(count)
You do not need a global variable. There are at least two other options. You can add an inout parameter to allLexicographicRecur to keep track of the count or you can have allLexicographicRecur return its count.
Here's your code using a return value:
func allLexicographicRecur(_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int) -> Int {
let length = string.count - 1
var data = data
var count = 0
for i in 0...length {
data[index] = String(string[i])
if index == last {
print(data.joined()) // Displays a combination. It is necessary to somehow calculate.
count += 1
} else {
count += allLexicographicRecur(string, data, last, index + 1)
}
}
return count
}
func allLexicographic(_ l: Int) -> Int {
let alphabet = "abc"
let data = Array(repeating: "", count: l)
let string = alphabet.sorted()
return allLexicographicRecur(string, data, l - 1, 0)
}
print(allLexicographic(3))
Here's your code updated to use an inout parameter.
func allLexicographicRecur(_ string: [String.Element], _ data: [String], _ last: Int, _ index: Int, _ count: inout Int){
let length = string.count - 1
var data = data
for i in 0...length {
data[index] = String(string[i])
if index == last {
print(data.joined()) // Displays a combination. It is necessary to somehow calculate.
count += 1
} else {
allLexicographicRecur(string, data, last, index + 1, &count)
}
}
}
func allLexicographic(_ l: Int) -> Int {
let alphabet = "abc"
let data = Array(repeating: "", count: l)
let string = alphabet.sorted()
var counter = 0
allLexicographicRecur(string, data, l - 1, 0, &counter)
return counter
}
print(allLexicographic(3))
You can not mange the count without global variable because of recursive function. so the method you wrote in question is perfect as per the output you want to have.

how to get Int from elements of dictionary array. xcode

let products = ["гречка" : "12,3,68", "рис" : "7,1,74", "овсянка" : "12,6,65"]
let userInput = "р"
for pair in products { //
if pair.key.contains(userInput) {
let elements = pair.value.components(separatedBy: ",")
print(pair.key + " contains \(elements [0])")
I need elements [0] take unary operation: var = 150 + element [0]
This?
let products = ["гречка" : "12,3,68", "рис" : "7,1,74", "овсянка" : "12,6,65"]
let userInput = "р"
for pair in products { //
if pair.key.contains(userInput) {
let elements = pair.value.components(separatedBy: ",")
let number = 150 + Int(elements[0])!
print(pair.key + " contains \(number)")
}
}

How would I go about categorizing items within an Array in swift?

In swift, I want to categorize items in an existing array and place them accordingly in one new string.
Here is an example of what I want to do:
originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
resultingString = "hotdog x 3, fries x 2, coke x 2"
How would I go about doing this?
Try this:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var dict = [String: Int]()
let resultString = originalArray.reduce(dict) { _, element in
if dict[element] == nil {
dict[element] = 1
} else {
dict[element]! += 1
}
return dict
}
.map { "\($0) x \($1)" }
.joinWithSeparator(", ")
If you want to keep the original order of the array (ie: hotdog, fries, coke), the code is slightly more complicated:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var dict = [String: (index: Int, count: Int)]()
let resultString = originalArray.enumerate()
.reduce(dict) { _ , e in
if let value = dict[e.element] {
dict[e.element] = (index: value.index, count: value.count + 1)
} else {
dict[e.element] = (index: e.index, count: 1)
}
return dict
}
.sort { return $0.1.index < $1.1.index }
.map { "\($0) x \($1.count)" }
.joinWithSeparator(", ")
print(resultString)
I think this will help you:
let originalArray = ["hotdog","fries","hotdog","coke","coke","fries","hotdog"]
var resultingString = ""
var counts:[String:Int] = [:]
for item in originalArray {
counts[item] = (counts[item] ?? 0) + 1
}
resultingString = counts.map { (key, value) -> String in
return "\(key) x \(value)"
}.joinWithSeparator(",")
print(resultingString)
Here is the output: coke x 2, hotdog x 3, fries x 2

Resources