In IBM Conversation, if we make a context variable array that contains other arrays (like entities) then it becomes a string array. As per the documentation, you cannot perform array methods like size() or length() on string arrays. Any way to perform such functions on string array?
There is a difference between array and string type in Watson Conversation Service. To get the information about size of an array - that is to get the information about the number of elements contained by the array type one can use the size() method.
For type string to get the information about the number of characters in a string one can use length() method.
Here is an example of both. The string looks like an array but it is a string (enclosed by quotes "". Notice the array type lacking the quotes around it:
{
"context": {
"my_string" : "[\"one\", \"two\", \"three\"]",
"my_array": [
"one",
"two",
"three"
]
},
"output": {
"text": {
"values": [
"This is string size: <?$my_string.length()?>. This is my array size: <? context.my_array.size()?>"
],
"selection_policy": "sequential"
}
}
}
Here is the answer from the dialog:
This is string size: 23. This is my array size: 3
Function length() is supported on string types.
Function size() is supported on array types.
I think the example in the documentation might be confusing you.
You can nest arrays, even string arrays, and still manipulate them as array data types. The intention of the example you reference in the documentation was to show that if you include an array context variable in a dialog response as part of a string, the array is treated as a string data type.
For example, you can specify this in the JSON editor for a dialog node:
{
"context": {
"array": [
"one",
"two"
],
"array_of_strings": [
"<? $array ?>",
"three",
"four"
],
"string_array": "this is an array: $array"
},
When you execute the node in the "Try it out" panel, and then check the context variable values, they look like this:
$array
["one","two"]
$array_of_strings
[["one","two"],"three","four"]
$string_array
"this is an array: [\"one\",\"two\"]"
Note: I was able to include the first array as an array data type in my $array_of_strings context variable. It is not until I include the array in a string that it acts like a string. I hope that makes sense?
Related
I am curious if there is any way in Swift to declare a multi-dimensional array that has a specific type(for this example we'll say Float) but isn't confined to a fixed number of dimensions(E.g., let arr: Array<Array<Float>>)?
I'd like to create a function that accepts a multi-dimensional array and currently the only way I'm aware of is:
func testFunction(arr: [Any]) {}
This is problematic though as it doesn't specify the actual scalar type of the array. As the type Any implies, this function can accept anything that is stuck inside of an Array. Any ideas?
Not with just an Array. Each array needs to know what type it contains. To contain an arbitrary number of dimensions, each array would need to be able to hold either a Float or an Array.
You could possible do something custom with an enum that has two cases.
enum MultidimensionalArray<Element> {
case array([MultidimensionalArray<Element>])
case values([Element])
}
but you'll probably have add a bunch more methods to it based on how you want to use ie.
How about generics
func testFunction<T>(arr: [T]) { }
T is a specific type and can be anything even
let foo = [[[[Float]]]]()
testFunction(arr: foo)
I found a way that makes it pretty simple to do what I'm after with some generic constraints and extensions.
protocol TypedNDArrayProtocol {}
// Make the type you are trying enforce conform to our protocol
extension Float: TypedNDArrayProtocol {}
// Now make Array conform to the same protocol while constraining
// it to only elements that *also* conform to this protocol
extension Array: TypedNDArrayProtocol where Element: TypedNDArrayProtocol {}
func testFunction(arr: Array<TypedNDArrayProtocol>) {}
This creates a sort of recursive conformance where the Array is allowed to accept either another Array, or a Float. If it is an Array, that Array can again only accept another Array or a Float and so on. This way you can use an arbitrary number of dimensions, but it must eventually terminate with a specific type; in this case a Float.
// This will work
testFunction(arr: [1.0, 2.0])
// This will also work
testFunction(arr: [[[3.0], [4.0]], [[5.0], [6.0]]])
// This will NOT work
testFunction(arr: [[[3], [4]], [[5], [6]]])
// Neither will this
testFunction(arr: [[["3"], ["4"]], [["5"], ["6"]]])
I'm playing around with Swift trying to make it look more "dynamically typed" – just for fun, no production value expected.
Now I'm stuck with overwriting behavior of converting builtin types to String.
For example, I'd like to see this output for Array:
let nums = [1, 2, 3]
print(nums) // "I'm an array"
So far I tried to
make an extension to NSArray (not compiles)
implement CustomStringConvertible (not compiles)
make an extension to Array (compiles, changes nothing)
Seems like I'm on the wrong path:
extension Array: CustomStringConvertible {
public var description: String { return "An array" }
}
gives the warning:
Conformance of 'Array' to protocol 'CustomStringConvertible' was already stated in the type's module 'Swift'
Is this doable in Swift?
This does not work because Array overrides description. If array did not override it then it would print "An array". The class method 'wins' over the extension.
extension Array {
public var description: String { return "An array" }
}
You could create a Wrapper class for your array. It's a workaround but doesn't override array's description itself.
class ArrayWrapper<T> : CustomStringConvertible{
var array : Array<T> = Array<T>()
var description: String { return "An array" }
}
You could then use it like this.
var array = ArrayWrapper<Int>()
array.array = [1,2,3]
print(array) //prints "An Array"
print(array.array) //still prints "[1, 2, 3]"
Seems like it is not possible to neither subclass nor overwrite a builtin Array type.
We could use a wrapper though (credits to #Yannick) and implement a ArrayLiteralConvertible protocol, so we could use square brackets for initialization.
struct Array<T> {
let array: [T]
}
extension Array: ArrayLiteralConvertible {
init(arrayLiteral elements: T...) {
self.array = elements
}
}
extension Array: CustomStringConvertible {
var description: String { return "An array" }
}
let array = [1,2,3]
print(array) // "An array\n"
Swift does not allow you to provide a protocol override for a type that already declares that protocol:
Imagine that you have a set of integers and you want to override the default implementation of CustomStringConvertible for a Set
The simplest answer to all of this is: you can't, and that's a feature not a bug. Set isn't your type and you don't get to change its already-defined behavior like this.
The capability to intercept and alter the behavior of a type to do something different to what that type is originally designed to do is powerful, but fraught with downsides. In this case, you've chosen a fairly benign thing to alter, but in other cases doing this could do all sorts of damage to assumed invariants of a type by changing its program-wide behavior.
The best way to alter a type to do something different like this is to wrap it in your own low-cost struct. Unfortunately this does mean writing a fair amount of boilerplate for forwarding – though less and less these days as we gain features like synthesized conformances and dynamic member lookup. Hopefully someday we'll get features that do make easier to create a newtype with customized behavior.
https://forums.swift.org/t/whats-the-best-way-to-override-customstringconvertible-for-a-collection/24844
Just got a quick array question it might be a little stupid but im kind of new to coding, what is the difference between the code here:
var items:[String]
so from my understanding here you are defining the variable 'items' as an empty array string. items is of type array
var items: [String] = ()
here you are defining items as an empty array but shouldn't it written as:
var items = [String]()
or is this essentially the same code
This:
var items:[String]
means that you are declaring a variable named items that will be an array of String instances. However, you are not initializing that variable to any initial value. The compiler will not let you use this variable before it is initialized with a value, because you are not declaring the type ([String]) to be optional ([String]?), so it must be initialized and contain a non-nil value to be used by your code.
This:
var items: [String] = ()
means that you are declaring a variable named items that should be an array of String instances, but you are trying to initialized it with the value (), which in Swift is synonymous with Void. The compiler will not allow this. A similar, valid notation would be: var items: [String] = [] which uses an empty array of unspecified type ([]) to initialize the value. Since you declared items to be an array of String values, the compiler can infer that the untyped empty array ([]) should be an empty array of String values ([String]) and will allow it.
This:
var items = [String]()
is declaring a variable named items that you aren't explicitly specifying the type for, and immediately initializing it with an empty array of String values. From this, the compiler can infer the type of the variable is [String] so you don't need to declare it.
var items = [String]() is called initializer syntax. It means you're allocating memory for the future storage of an array of strings.
However, by doing var items:[String] you are not providing an initializer. This will cause an error--consider conceptually that you are pointing to an area of memory that you have not allocated space for. There's nowhere for additional variables to go!
On the other hand, var items: [String] = () doesn't seem to be any kind of standard syntax. It seems like you're casting an array of strings as void. This shouldn't compile.
I'm currently working on introspection in Swift 2 and have Problems getting the specific type for an Array (in this example an Array<String>).
var prop = obj.valueForKey("strings")!
if prop is Array<String> {
println("true")
}
if prop is Array<Int> {
println("true")
}
Output is:
true
true
while it should be
true
false
Is there a way to find out the type for the members of the Array? For example, if I daclared the Array as Array<String> I want to get String or at least be able to check if it is.
MirrorType also did not lead to any success on that by now.
There are 2 ways to achieve what you want:
if prop.dynamicType == Array<Int>.self (or [Int].self) which is better than if prop.dynamicType == [Int]().dynamicType { because [Int]() creates an unused instance of "array of integers".
Typically, when you check if an array is specific-typed, you plan to use it
in a certain way (as a result, you will likely cast your array to
[Int]). Having that said, I recommend using if let arrayOfInts =
prop as? Array<Int> {. Using this construct, you will check for
type compatibility and prepare your array to be treated in a special way (using the casted arrayOfInts reference).
Anyway, it's up to you to decide what to do.
Perhaps what you want is the type of each individual item inside the Array rather than the type of the Array itself? If you are using collection types in Swift, all the items stored in the Array (or Dictionary) are of the same type (except if you declare the Array as Array for example to break the rules... which is not usually necessary, or wanted).
By declaring an Array with its initially values you are automatically telling the compiler what type they are. If you do something like this:
let obj = [1,2,3]
var property = obj[0]
if property is String {
print("true")
}
if property is Int {
print("true")
}
The compiler will already tell you that property is String always fails, and there is actually no need to do that test (because we already know that it will always fail).
If you are working with Objective-C APIs and types on the other hand, there may be occasions where you will need to test for type, this is a good example of testing for type in an Objective-C collection that has items of different types:
let userDefaults = NSUserDefaults.standardUserDefaults()
let lastRefreshDate: AnyObject? = userDefaults.objectForKey("LastRefreshDate")
if let date = lastRefreshDate as? NSDate {
print("\(date.timeIntervalSinceReferenceDate)")
}
Hope this helps.
I have an array of type [String]
let names = ["Joffrey", "Cersei", "Mountain", "Hound"]
I have a function which takes an array of [Any] type.
func printItems(items: [Any]){
for item in items {
print(item)
}
}
Now when I call the function with names as parameters,
printItems(names)
I get an error Cannot invoke 'printItems' with an argument list of type '([String])'.
Any is just a typealias for a protocol which all types implicitly conform to.
Thoughts?
This is a surprising limitation of Swift. You can't cast an array to type [Any] so you can't pass it to a function taking type [Any]. You can use map to cast each item of the array:
printItems(names.map {$0 as Any})
But, the right way to do this in Swift is to use Generics:
func printItems<T>(items: [T]) {
for item in items {
print(item)
}
}
let names = ["Joffrey", "Cersei", "Mountain", "Hound"]
let numbers = [3.1416, 2.71818, 1.4142, 1.618034]
printItems(names) // This now works
printItems(numbers) // This works too
While every type conforms Any, this is not the same as it being a universal implicit superclass that all types inherit from.
When you cast a type to a protocol, you create a new value with a different structure. So for a string to be of type Any, it needs to be physically transformed from the String representation:
sizeof(String) // 24 bytes (on 64-bit, anyway)
to the Any representation:
sizeof(Any) // 32 bytes, includes some meta data
// about what the type really is
Since value types are held directly in the array, the array would be a very different shape so under the hood the compiler would have to do the equivalent of this:
names.map { $0 as Any } // create a new array, with the Any versions
Swift could perhaps automate this process for you (it does if you pass a single variable into a function that takes Any). But personally I’m glad it doesn’t, I’d rather this be more explicit – suppose your array was huge, this would be a lot of processing happening implicitly under the hood.
This is different from when you have an array of reference types, all of which are pointers to the actual data and so all the same size, and which need no transformation when upcasting:
class C { }
class D: C { }
let d = D()
let c: C = d
unsafeBitCast(d, UnsafePointer<Void>.self) // these value will
unsafeBitCast(c, UnsafePointer<Void>.self) // be the same
So saying “this array of [D] is really an array of [C]” is just a matter of the compiler agreeing the types can be substituted, no data transformation needs to take place:
// so this works fine,
// no runtime transformation needed:
func f(cs: [C]) { }
let ds = [D(),D()]
f(ds)
But protocols still are different from superclass references when used with classes:
protocol P { }
extension C: P { }
sizeofValue(C()) // 8 bytes (just a pointer)
sizeofValue(C() as P) // 40 bytes
func g(ps: [P]) { }
g(ds) // won’t compile, needs transformation
You need to explicitly put in your let declaration that you
are declaring an Any array and not a specific type array.
With your current declaration, Swift will evaluate it to [String] array.
and not as [Any] array.
To fix your problem just do the following:
let names : [Any] = ["Joffrey", "Cersei", "Mountain", "Hound"]
If you want to retain your let declaration, use AnyObject
in your printItems function and it will be accepted by Swift.
func printItems(items: [AnyObject]){
for item in items {
print(item)
}
}