I have a series of animals in an array that I am joining via a ,.
However, I want the last animal to have an and before it, like so:
cow, giraffe, horse, mongoose, leopard, and snake.
The join method in Swift gives me everything except the and, and I am not sure how I can add any specifiers.
Sorry if this is a noob question, still getting the hang of this.
You could write you own join function like this:
func myjoin(separator: String, var elements:[String]) -> String {
elements[elements.count - 1] = "and " + elements[elements.count - 1]
return elements.joinWithSeparator(separator)
}
var animals = ["cow", "giraffe", "horse", "mongoose", "leopard", "snake"]
myjoin(", ", elements: animals)
Here's a version that does the "right thing" for lists with 1 or 2 elements:
func myjoin2(var elements:[String]) -> String {
let count = elements.count
let separator = (count == 2) ? " " : ", "
if count > 1 {
elements[count - 1] = "and " + elements[count - 1]
}
return elements.joinWithSeparator(separator)
}
myjoin2(["cat"]) // "cat"
myjoin2(["cat", "dog"]) // "cat and dog"
myjoin2(["cat", "dog", "pig"]) // "cat, dog, and pig"
Related
I want to fetch enum attributes in a module using AttriBaseType and print it's elements.
Basically I want to know the usage of AttriBaseType in dxl.
For retrieving enum values, if you really want to use it explicitly, you can do it perhaps like this:
AttrType at
for at in current Module do {
print (at.name) " -- " (at.type) "\n"
AttrBaseType abt = at.type
if (abt == attrEnumeration) {
print "it is an " abt "\n"
int enumCount = at.size
int index
for (index = 0; index < enumCount; index++) {
// value, related number
print at.strings[index] ", " at.values[index] "\n"
}
print "\n"
}
}
I'm trying loop though a very large table in Lua that consists of mixed data types many nested tables. I want to print the entire data table to the console, but I'm having trouble with nested loops. When I do a nested loop to print the next level deep Key Value pairs I get this error bad argument #1 to 'pairs' (table expected, got number) because not all values are tables.
I've tried adding a if type(value) == table then before the nested loop but it never triggers, because type(value) returns userdata whether they are ints, strings or tables.
EDIT: I was wrong, only tables are returned as type userdata
My table looks something like this but hundreds of pairs and can be several nested tables. I have a great built in method printall() with the tool I'm using for this but it only works on the first nested table. I don't have any control over what this table looks like, I'm just playing with a game's data, any help is appreciated.
myTable = {
key1 = { value1 = "string" },
key2 = int,
key3 = { -- printall() will print all these two as key value pairs
subKey1 = int,
subKey2 = int
},
key4 = {
innerKey1 = { -- printall() returns something like : innerKey1 = <int32_t[]: 0x13e9dcb98>
nestedValue1 = "string",
nestedValue2 = "string"
},
innerKey2 = { -- printall() returns something like : innerKey2 = <vector<int32_t>[41]: 0x13e9dcbc8>
nestedValue3 = int,
nestedValue4 = int
}
},
keyN = "string"
}
My loop
for key, value in pairs(myTable) do
print(key)
printall(value)
for k,v in pairs(value) do
print(k)
printall(v)
end
end
print("====")
end
ANSWER : Here is my final version of the function that fixed this, it's slightly modified from the answer Nifim gave to catch edge cases that were breaking it.
function printFullObjectTree(t, tabs)
local nesting = ""
for i = 0, tabs, 1 do
nesting = nesting .. "\t"
end
for k, v in pairs(t) do
if type(v) == "userdata" then -- all tables in this object are the type `userdata`
print(nesting .. k .. " = {")
printFullObjectTree(v, tabs + 1)
print(nesting .. "}")
elseif v == nil then
print(nesting .. k .. " = nil")
elseif type(v) == "boolean" then
print(nesting .. k .. " = " .. string.format("%s", v))
else
print(nesting .. k .. " = " .. v)
end
end
end
type(value) returns a string representing the type of value
More information on that Here:
lua-users.org/wiki/TypeIntrospection
Additionally your example table has int as some of the values for some keys, as this would be nil those keys are essentially not part of the table for my below example i will change each instance of int to a number value.
It would also make sense to recurse if you hit a table rather than making a unknown number of nested loops.
here is an example of working printAll
myTable = {
key1 = { value1 = "string" },
key2 = 2,
key3 = { -- printall() will print all these two as key value pairs
subKey1 = 1,
subKey2 = 2
},
key4 = {
innerKey1 = { -- printall() returns something like : innerKey1 = <int32_t[]: 0x13e9dcb98>
nestedValue1 = "string",
nestedValue2 = "string"
},
innerKey2 = { -- printall() returns something like : innerKey2 = <vector<int32_t>[41]: 0x13e9dcbc8>
nestedValue3 = 3,
nestedValue4 = 4
}
},
keyN = "string"
}
function printAll(t, tabs)
local nesting = ""
for i = 0, tabs, 1 do
nesting = nesting .. "\t"
end
for k, v in pairs(t) do
if type(v) == "table" then
print(nesting .. k .. " = {")
printAll(v, tabs + 1)
print(nesting .. "}")
else
print(nesting .. k .. " = " .. v)
end
end
end
print("myTable = {")
printAll(myTable, 0)
print("}")
I came across tables that have square brackets around keys:
local commands_json =
{
["request"] = {
["application"] = PW_APPLICATION,
["push_token"] = deviceToken
}
}
Can the square brackets be omitted?
It's simply the long form of specifying keys in a table. You can put any value between the [] (except nil. And floating-point NaNs). Whereas without them, you can only use identifiers.
For example:
tbl =
{
key name = 5,
}
That's a compile error, since "key name" isn't an identifier (due to the space). This works:
tbl =
{
["key name"] = 5,
}
And this:
tbl =
{
"key name" = 5,
}
Is also a compile error. If Lua sees a naked value like this, it thinks you're trying to add to the array part of the table. That is, it confuses it with:
tbl =
{
"key name",
}
Which creates a 1-element array, with tbl[1] equal to "key name". By using [], the compiler can easily tell that you meant for something to be a key rather than the value of an array element.
The long form also lets you distinguish between:
local name = "a name";
tbl =
{
["name"] = 5,
[name] = 7,
}
The second part means to evaluate the expression name, the result of which will be the key. So this table has the keys "name" and "a name".
You cannot omit the brackets
> x = { 'a' = 1 }
stdin:1: '}' expected near '='
the correct code is
> x = { ['a'] = 1 }
> print(x['a'])
1
or
> x = { a = 1 }
> print(x['a'])
1
However, the second one has its limitations. What if you want to have a key called "-"?
> x = { - = 1 }
stdin:1: unexpected symbol near '='
> x = { '-' = 1 }
stdin:1: '}' expected near '='
again the correct way is to use brackets
> x = { ['-'] = 1 }
> print(x['-'])
1
Or you want to create a field of name which is contained in a variable called a?
> a = 'cat'
> x = { [a] = 1 }
> print(x['cat'])
1
Brackets are used as a general form of key creation, they give you ability to put any hashable object as a key - not only strings.
I have two objects. One called EstimateItem and the other one is called Part (Part class is inherited from Realm's Object class). One EstimateItem can have multiple Parts.
class EstimateItem {
var parts: [Part]?
}
There's an array of EstimateItems with different numbers of Parts in each instance.
+--------------------------------+---------------------------------+
| EstimateItem | Parts |
+--------------------------------+---------------------------------+
| Line Item 1 - RnR WDH - Twins | Epoxy / Wood for lami |
| (single) | |
| | |
| Line Item 2 - RnR WDH - Twins | Epoxy / Wood for lami |
| (double) | |
| | |
|Line Item 3 - Install sash lock |Epoxy / Wood for lami / Sash lock|
+--------------------------------+---------------------------------+
I need to group them by specific Part. It should look something like this.
How do I do this?
I couldn't figure out a way to do this while the parts are attached to individual item so I tried laying them all out in an array of (part: Part, item: EstimateItem) tuples.
var groups = [(part: Part, item: EstimateItem)]()
for item in estimateItemsArray {
if let parts = item.parts {
for part in parts {
groups.append((part, item))
}
}
}
// Epoxy - RnR WDH - Twins (single)
// Wood for lami - RnR WDH - Twins (single)
// Epoxy - RnR WDH - Twins (double)
// Wood for lami - RnR WDH - Twins (double)
// Epoxy - RnR WDH - Twins (single)
// Wood for lami - RnR WDH - Twins (single)
// Sash lock, traditional - Install sash lock
And then group it.
But I'm still stuck. Also I feel like I'm overcomplicating it and I was wondering if there's an easier and more Swifty way of doing this.
What I came up with trying to find a more swifty way of doing this is the following:
let parts = Set(estimateItemsArray.flatMap{ $0.parts ?? [] })
let partMap = parts.map { part in
return (part, estimateItemsArray.filter {
$0.parts?.indexOf(part) != nil
}
)
}
partMap now contains tuples of the form (Part, [EstimateItem]). The only requirement is for Part to conform to Hashable or something related - in my test I just let Part inherit from NSObject.
Explanation:
create an array of all the available parts (Set to ensure uniqueness)
loop over the array mapping and returning a tuple of
the actual part
loop over estimateItemsArray filtering out the items that have the current part in their list
The complete test-data looks like this
/* the now classes, both include some identifier to distinguish them */
class Item {
var n : String
var parts : [Part]? = [Part]()
init(n:String) {
self.n = n
}
}
class Part : NSObject {
var n : String
init(n:String) {
self.n = n
}
}
/* set up the test data */
let item1 = Item(n: "item 1")
let item2 = Item(n: "item 2")
let item3 = Item(n: "item 3")
let part1 = Part(n: "part 1")
let part2 = Part(n: "part 2")
let part3 = Part(n: "part 3")
item1.parts = [part1, part2]
item2.parts = [part1, part3]
item3.parts = [part1, part2, part3]
var arrItems = [item1, item2, item3]
/* actual logic */
let parts = Set(arrItems.flatMap{ $0.parts ?? [] })
let partMap = parts.map { part in
return (part, arrItems.filter {
$0.parts?.indexOf(part) != nil
}
)
}
/* final output */
partMap.forEach { entry in
print("part \(entry.0.n)")
entry.1.forEach {
print("contains \($0.n)")
}
}
Outputting:
part part 1
contains item 1
contains item 2
contains item 3
part part 3
contains item 2
contains item 3
part part 2
contains item 1
contains item 3
If you cannot inherit from NSObject like I initially though, make your class Part conform to Hashable which is the requirement for sets:
class Part : Hashable {
var n : String
init(n:String) {
self.n = n
}
var hashValue: Int {
return n.hashValue // you basically have to provide some kind of logic based on *your* Part object
}
}
func ==(lhs: Part, rhs: Part) -> Bool {
return lhs.hashValue == rhs.hashValue
}
For some reason the DXL interpreter does not take into account the fact that I am decrementing i at the end of the for loop. I am trying to navigate through the arrObj[] array by changing the value of "i". I have some buttons that increment(for next object) and decrement(for previous object) the value respectively. Doing the same thing with a while loop crashes the application.
Is there any way to control the index or will DXL always remember the previous value and increment it (even if the user changes it's value within the code).
Here's a snippet from my code:
for i in 0:(iTotalObj-1) do
{
sAuxType = arrObj[i]."ObjectType"
sAuxNr = number(arrObj[i]) " "
sAuxObjTxt = arrObj[i]."Object Text"
print "\nAfter FOR:"i ""
if sAuxType == "Test-Case" then
{
set(testContent,"Index number: (" number(arrObj[i]) ") -> " arrObj[i]."Object Heading" "")
set(expectedResults, " ")
fillRow(sTesterName,sCfgSW,sCfgHW,arrObj[i])
block(dtbox)
}
if sAuxType == "Test-Step" then
{
set(testContent,"Index number: (" number(arrObj[i]) ") -> " arrObj[i]."Object Text" "")
set(expectedResults,richTextWithOle(arrObj[i]."ExpectedResult"))
fillRow(sTesterName,sCfgSW,sCfgHW,arrObj[i])
block(dtbox)
}
if sAuxType == "Test-Case-Description" then
{
set(testContent,"Index number: (" number(arrObj[i]) ") -> " arrObj[i]."Object Text" "")
set(expectedResults, "Please check the description throroughly")
fillRow(sTesterName,sCfgSW,sCfgHW,arrObj[i])
block(dtbox)
arrObj[i].("TestResult " iTR "") = "n/a"
arrObj[i].("FR " iTR "") = "n/a"
}
i--
print "\nAfter DECREMENT:"i ""
}
On the output box I'll get the following:
After FOR:0
After DECREMENT:-1
After FOR:1
After DECREMENT:0
After FOR:2
After DECREMENT:1
With that type of for loop I believe DOORS is forcing i to the next value in the set. You should be able to use this type of loop instead:
for(i=0; i<(iTotalObj-1); i++) {
...
}
This loop will allow you to manipulate i inside the loop.