Swift, handle Arrays and Datatypes (Split String from String) [duplicate] - arrays

This question already has answers here:
How does String.Index work in Swift
(4 answers)
Closed 6 years ago.
I just started with Swift a few days ago and I am struggling with all the different Datatypes...
Lets say we do this:
var myarray = ["justin", "steve", "peter"]
var newString = myarray[2]
so why I cant now print just the "p" from "peter"?
print(newString[0])
---> gives me an error:
"'subscript' is unavailable: cannot subscript String with an Int"
in this topic:
[Get nth character of a string in Swift programming language
it says:
"Note that you can't ever use an index (or range) created from one string to another string"
But I cant imagine, that there isn't way to handle it...
Because When I do this:
var myarray = ["justin", "steve", "p.e.t.e.r"]
var newString = myarray[2]
let a : [String] = newString.componentsSeparatedByString(".")
print(a[2])
then it works. It prints (in this case) "t".
So how I can split it "SeparatedByString" 'Nothing'?
Im sure to solve this will help me also at many other problems.
I hope I postet the question in the way it should be done.
Thank you for any solution or tips :)

The instance method componentsSeparatedByString applied to a String instance yields an array of String instances, namely [String]. The elements of an array can be indexed in the classic Java/C++ fashion (let thirdElement = array[2]).
If you'd like to split your String instance ("peter") into an array of single character String instances, you can make use of the CharacterView property of a String instance, and thereafter map each single Character in the CharacterView back to a single-character String instance
let str = "peter"
let strArray = str.characters.map(String.init(_:)) // ["p", "e", "t", "e", "r"]
let thirdElement = strArray[2] // t
This is quite roundabout way though (String -> CharacterView -> [String] -> String), and you're most likely better off simply looking at the excellent answer (covering direct String indexing) in the dupe thread dug up by #Hamish:
How does String.Index work in Swift 3
The possible corner case where the above could be applicable, as pointed out by Hamish below, is if you very frequently need access to characters in the String at specific indices, and like to make use of the O(1) random access available to arrays (more so applicable if you are working with immutable String:s, such that the corresponding String array only needs to be generated once for each immutable String instance).

Related

Use of Separator while accessing arrays

I'm learning Swift through Youtube using online compilers on Windows and while learning to access arrays, I experienced that I had to use "," as separator in place of "\" inside the print function. But "\" was used in the video I was watching (she was using Xcode on Mac). What's the reason behind this? I've provided the code below.
import Foundation
let friends = ["Alisa", "Alice", "Joseph"]
print("friend 1: " ,(friends[1]))
In String Interpolation each item that you insert into the string literal is wrapped in a pair of parentheses, prefixed by a backslash \(var)
let friends = ["Alisa", "Alice", "Joseph"]
print("friend 1: \(friends[0])")
Or you can create a string with Format Specifiers
print(String(format:"friend 2: %#", friends[0]))
print statement accepts a list of Any objects. In the below line both objects are separated by comma
print("friend 1: " ,(friends[1]))//friend 1: Alice
print(1,2,3)//1 2 3
The technique is String Interpolation.
You construct a new string from string literals.
let name = "Bob"
//Returns: Hi Bob"
print("Hi \(name)")
Read more at: https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html#ID292
A string literal is a predefined string value.
//This is a string literal.
let name = "Bob"
You can still use array values with String Interpolation.
let friends = ["Alisa", "Alice", "Joseph"]
let friend1 = friends[1]
print("friend 1: \(friend1)")
print("friend 1: \(friends[1])")
//These 2 print methods return same value.
//One is a constant, one is an array element.

How do I create a string of array combinations given a list of "source code" strings?

Basically, I’m given a list of strings such as:
["structA.structB.myArr[6].myVar",
"structB.myArr1[4].myArr2[2].myVar",
"structC.myArr1[3][4].myVar",
"structA.myArr1[4]",
"structA.myVar"]
These strings are describing variables/arrays from multiple structs. The integers in the arrays describe the size each array. Given a string has a/multiple arrays (1d or 2d), I want to generate a list of strings which go through each index combination in the array for that string. I thought of using for loops but issue is I don’t know how many arrays are in a given string before running the script. So I couldn’t do something like
for i in range (0, idx1):
for j in range (0, idx2):
for k in range (0, idx3):
arr.append(“structA.myArr1[%i][%i].myArr[%i]” %(idx1,idx2,idx3))
but the issue is that I don’t know how I can create multiple/dynamic for loops based on how many indexes and how I could create a dynamic append statement that changes per each string from the original list since each string will have a different number of indexes and the arrays will be in different locations of the string.
I was able to write a regex to find all the index for each string in my list of strings:
indexArr = re.findall('\[(.*?)\]', myString)
//after looping, indexArr = [['6'],['4','2'],['3','4'],['4']]
however I'm really stuck on how to achieve the "dynamic for loops" or use recursion for this. I want to get my ending list of strings to look like:
[
["structA.structB.myArr[0].myVar",
"structA.structB.myArr[1].myVar",
...
"structA.structB.myArr[5].myVar”],
[“structB.myArr1[0].myArr2[0].myVar",
"structB.myArr1[0].myArr2[1].myVar",
"structB.myArr1[1].myArr2[0].myVar",
…
"structB.myArr1[3].myArr2[1].myVar”],
[“structC.myArr1[0][0].myVar",
"structC.myArr1[0][1].myVar",
…
"structC.myArr1[2][3].myVar”],
[“structA.myArr1[0]”,
…
"structA.myArr1[3]”],
[“structA.myVar”] //this will only contain 1 string since there were no arrays
]
I am really stuck on this, any help is appreciated. Thank you so much.
The key is to use itertools.product to generate all possible combinations of a set of ranges and substitute them as array indices of an appropriately constructed string template.
import itertools
import re
def expand(code):
p = re.compile('\[(.*?)\]')
ranges = [range(int(s)) for s in p.findall(code)]
template = p.sub("[{}]", code)
result = [template.format(*s) for s in itertools.product(*ranges)]
return result
The result of expand("structA.structB.myArr[6].myVar") is
['structA.structB.myArr[0].myVar',
'structA.structB.myArr[1].myVar',
'structA.structB.myArr[2].myVar',
'structA.structB.myArr[3].myVar',
'structA.structB.myArr[4].myVar',
'structA.structB.myArr[5].myVar']
and expand("structB.myArr1[4].myArr2[2].myVar") is
['structB.myArr1[0].myArr2[0].myVar',
'structB.myArr1[0].myArr2[1].myVar',
'structB.myArr1[1].myArr2[0].myVar',
'structB.myArr1[1].myArr2[1].myVar',
'structB.myArr1[2].myArr2[0].myVar',
'structB.myArr1[2].myArr2[1].myVar',
'structB.myArr1[3].myArr2[0].myVar',
'structB.myArr1[3].myArr2[1].myVar']
and the corner case expand("structA.myVar") naturally works to produce
['structA.myVar']

How to show elements of array?

I have a small problem. I created a large array.
It looks like this:
var Array = [
["text10", "text11", ["text01", "text02"]],
["text20", "text21", ["text11", "text12"]]
]
If we write this way: Array[0] that shows all the elements.
If we write this way: Array[0][0] that shows "text1".
If we write this way: Array[0][2] that shows
-2 elements
-- 0: "text01"
-- 1: "text02"
.
If we write this way: Array[0][2].count or Array[0][2][0] it will not work
How do I choose each item, I need these elements for the tableView
The problem basically is that your inner array is illegal. Swift arrays must consist of elements of a single type. You have two types of element, String and Array Of String. Swift tries to compensate but the result is that double indexing can’t work, not least because there is no way to know whether a particular element will have a String or an Array in it.
The solution is to rearchitect completely. If your array entries all consist of the same pattern String plus String plus Array of String, then the pattern tells you what to do; that should be a custom struct, not an array at all.
as #matt already answered but I want to add this thing
Why Array[0][2].count or Array[0][2][0] not work
If you Define array
var array = [
["text10", "text11", ["text01", "text02"]],
["text20", "text21", ["text11", "text12"]]
]
And when you type array you can see it's type is [[Any]] However it contains String as well as Array
So When you try to get Array[0][2] Swift does not know that your array at position 2 has another array which can have count
EDIT
What you are asking now is Array of dictionary I suggest you to go with model i.e create struct or class and use it instead of dictionary
Now If you want to create dictionary then
var arrOfDict = ["text10" : ["text01", "text02"] , "text11" : ["text11", "text12"]]
And you can access with key name let arrayatZero = arrOfDict["text10"] as? [String]

How do I get an item with subelements from an array in Swift? [duplicate]

This question already has answers here:
Pick a random element from an array
(16 answers)
Closed 4 years ago.
I have a class for quotes that contains an array full of quotes. The code below shows two. Each quote has an author, attribution, and Bools for hasSeen and hasSaved.
I want to show one random quote at a time. When the user refreshes the screen, they get another quote. When I put .randomElement()! on the array and print the results, I get appName.Quote.
Is there a way to access a random quote from this array? I want to be able to show the text and attribution to the end user.
var quotes:[Quote] = [
Quote(
quoteText: "The only way to make sense out of change is to plunge into it, move with it, and join the dance.",
quoteAttribution: "Alan Watts",
hasSeen: false,
hasSaved: false),
Quote(
quoteText: "Luck is what happens when preparation meets opportunity.",
quoteAttribution: "Seneca",
hasSeen: false,
hasSaved: false)
]
You can extend swift's Array to have this feature:
extension Array {
func randomItem() -> Element? {
if isEmpty { return nil }
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
And you access random Quote like this:
let quote = quotes.randomItem()
On a side note, since you are dealing with fixed/staitc content/structure, consider using tuple for storing Quote

Access first element of string in Ada

I have a string passed into a function, I would like to compare the first character of the string against a number.
I.E.
if String(1) = "3" then
When I compile I get:
warning: index for String may assume lower bound of 1
warning: suggested replacement String'First + 1
I would really like to make this right, but when I try "first" it actually grabs a number, not the character.
Is there a better way to do it?
I tried looking up the 'First concept, and the below site explains I'm actually getting the number of the index, not the actual contents: http://en.wikibooks.org/wiki/Ada_Programming/Types/array
For example,
Hello_World : constant String := "Hello World!";
World : constant String := Hello_World (7 .. 11);
Empty_String : constant String := "";
Using 'First I'll get:
Array 'First 'Last 'Length 'Range
Hello_World 1 12 12 1 .. 12
World 7 11 5 7 .. 11
Empty_String 1 0 0 1 .. 0
Based on that information, I can't get H from Hello world (for a comparison like if Hello_World(1) = "H" then)
EDIT:
So the way I initially was doing it was
(insert some variable name instead of string in this case)
String(String'First .. String'First) = "1"
So that works from what I can tell, however, rather then writing all that, I found out that
String(String'First) = '1'
Does the same thing but using char comparison, which makes a lot more sense!
Thanks for all the answers everyone!
Strings are the biggest bugaboo for newbie Ada coders; particularly so for those who are already experts at dealing with strings in Cish languages.
Ada strings (in fact all Ada arrays) are not 0 based like C, or 1-based like Fortran. They are based however the coder felt like it. If someone wants to index their string from 10 ... 200, they can. So really the safest way to acces characters in an Ada string is to use the 'first attribute (or better yet, loop through them using 'range or 'first .. 'last).
In your case it looks like you want to get at only the first character in the string. The easiest and safest way to do that for a string named X is X(X'first).
In pactice you would almost never do that though. Instead you would be looping through the string's 'first...'last looking for something, or just using one of the routines in Ada.Strings.Fixed.
The warning is suggesting you use:
String(String'First + Index)
Instead of just
String(Index)
There's something odd about the code in your question. First off, that you're calling your variable "String" and that it's of type "String". Ada will balk at that right off the bat.
And the warning statements you reproduce for that code fragment don't make sense.
Let's say your variable is actually called "Value", i.e.:
Value : String := "34543";
Value(1) is not the same as Value(Value'First + 1), because Value'First (in this declaration) is 1. So you end up referencing Value(1 + 1). You appear to be experiencing this because of mentioning that you can't reference the 'H' in a "Hello World" string.
Now the warning is valid, in that you're safer using 'First (and 'Last and 'Range) to reference array bounds. But you need to use the proper indexing if you're going to offset from the bound retrieved via 'First, typically using either 0-based or 1-based (in which case you need to offset by 1). Use whichever base is more appropriate and readable in your context.

Resources