Split an array into two, based on separator element - arrays

I have an array of strings and I'd like to split that into two. An array containing the elements before the separator, and another one after it.
let sourceArray = ["items that", "are", "split", "by a string"]
// String that splits this array: "split"
// Expected output: [["items that", "are"], ["by a string"]]
I tried joining the array into a string and using .components(), but that removes the actual elements of the original array. Is there a way to do this using a built-in method or do I need to loop over it?

You can try
let sourceArray = ["items that", "are", "split", "by a string"]
let index = sourceArray.split(separator: "split").map { Array($0) }
print(index)

You could do it this way :
var sourceArray = ["items that", "are", "split", "by a string"];
var array1 = [];
var array2 = [];
var firstArray = true;
for (var i = 0; i<sourceArray.lenght; i++){
if (sourceArray[i]!=="split") {
if (firstArray){
array1.push(sourceArray[i]);
}
else {
array2.push(sourceArray[i]);
}
}
else {
firstArray = false;
}
}
At the end of the loop, just join the two arrays into a third one if you want it like that : [array1,array2].

Related

loop to create array of arrays of same-length strings

I'm trying to create an array of arrays that are grouped according to their lengths (strings), such that the array below:
var testA = ["carts","carts","cars","cars","ca","ca", "ca","a","a","a","a"];
would become:
var sortedArrays = [["carts","carts"], ["cars","cars"],["ca","ca","ca"], ["a","a","a","a"]]
I am currently trying the loop below but simply cannot get this to work. I know it'll be something simple, but I've spent so long trying to complete this with no that it's proving incredibly frustrating.
var testA = ["carts","carts","cars","cars","ca","ca", "ca","a","a","a","a"];
var sortedArrays = [];
for(i=0; i < testA.length; i++){
longestWord = 0;
wordHolder = []
wordHolder.push(testA[i])
if (testA[i].length > longestWord){
longestWord = testA[i].length
wordHolder.push(testA[i])
}
sortedArrays.push(wordHolder)
}
Any help will be greatly appreciated
What about the following code (Swift, but it should be easy to reformulate it in other languages):
let testA = ["carts","carts","cars","cars","ca","ca", "ca","a","a","a","a"]
var maxLength = 0
for string in testA {
if string.count > maxLength { maxLength = string.count }
}
var sortedArrays: [[String]] = []
for nextLength in 0 ... maxLength {
let invertedLength = maxLength - nextLength
let nextArray = testA.filter { $0.count == invertedLength }
sortedArrays.append(nextArray)
}
This code creates also empty arrays, which can of course easily be skipped.
The question, of course, is what your requirements are. The code above is compact, but it is not fast for large arrays...
For large arrays, it would be better, first to sort testA, and then to extract the elements.
Sticking with java script, I was able to do the following. My assumption is the words are already sorted descending by length and that there is only one word of each length. That's based on what you were doing. I think what was going on is that too much was getting initialized or reset each time through the loop.
var testA = ["carts", "carts", "cars", "cars", "ca", "ca", "ca", "a", "a", "a", "a"];
var sortedArrays = [];
var wordHolder = []; // took outside loop to ensure initialized
var curLength = testA[0].length;// assuming here that testA not empty
for (var i = 0; i < testA.length; i++) {
if (testA[i].length === curLength) { // more of the same
wordHolder.push(testA[i]);
} else { // new block starts
curLength = testA[i].length;
sortedArrays.push(wordHolder);
// alert (wordHolder)
// alert (sortedArrays)
wordHolder = [];
wordHolder.push(testA[i]);
}
}
sortedArrays.push(wordHolder);// add the last one

Return array without first element with updated index (Swift)

I have an array let animals = ["cat", "dog", "elephant"]
And I want to return a new array without first element, but when I use
let animalsWithoutCat = animals[1...animals.count - 1]
// or
let animalsWithoutCat = animals.dropFirst()
I get an array with animals' index, so "dog" is 1 and "elephant" is 2.
I want an array with updated index (started with 0). Fewer lines of code is preferred ))
Thanks for any help!
What you want is the tail of the array.
If you implement it in an extension like this
extension Array {
var tail: Array {
return Array(self.dropFirst())
}
}
you can call it like this:
let animals = ["cat", "dog", "elephant"]
let animalsWithoutCat = animals.tail
If the array is empty tail is an empty array.
Use:
let animals = ["cat", "dog", "elephant"]
var animalsWithoutCat = animals
animalsWithoutCat.removeFirst() // Removes first element ["dog", "elephant"]
Or us it as an extention:
extension Array {
func arrayWithoutFirstElement() -> Array {
if count != 0 { // Check if Array is empty to prevent crash
var newArray = Array(self)
newArray.removeFirst()
return newArray
}
return []
}
Simply call:
let animalsWithoutCat = animals.arrayWithoutFirstElement()

Swift: Get multiple array values like "x"

For example, I have an array like var myArray = ['player_static.png', 'player_run0.png', 'player_run1.png', 'player_run2.png', 'player_jump0.png', 'player_jump1.png']
Is there any simple way to get only the "player_runX.png" images?
You can use filter to get all elements that hasPrefix("player_run"):
let myArray = ["player_static.png", "player_run0.png", "player_run1.png", "player_run2.png", "player_jump0.png", "player_jump1.png"]
let playerRuns = myArray.filter{$0.hasPrefix("player_run")}
print(playerRuns) //["player_run0.png", "player_run1.png", "player_run2.png"]
One way to do this would be to iterate over the array and retrieve the elements that match the pattern. A very quick sample would be something like this:
var myArray = ["player_static.png", "player_run0.png", "player_run1.png", "player_run2.png", "player_jump0.png", "player_jump1.png"]
func getSubArray(array:[String],prefix:String) -> [String]
{
var newArray = [String]()
for img in array
{
if img.substringToIndex(img.startIndex.advancedBy(prefix.characters.count)) == prefix
{
newArray.append(img)
}
}
return newArray
}
var test = getSubArray(myArray, prefix: "player_run")

Reduce a string to a dictionary in Swift

What woudl be a simple way to reduce a string like AAA:111;BBB:222;333;444;CCC:555 to a dictionary in Swift. I have the following code:
var str = "AAA:111;BBB:222;333;444;CCC:555"
var astr = str.componentsSeparatedByString(";").map { (element) -> [String:String] in
var elements = element.componentsSeparatedByString(":")
if elements.count < 2 {
elements.insert("N/A", atIndex: 0)
}
return [elements[0]:elements[1]]
}
The code above produces an Array of Dictionaries:
[["A": "111"], ["BBB": "222"], ["UKW": "333"], ["UKW": "444"], ["CCC": "555"]]
I want it to produce
["A": "111", "BBB": "222", "UKW": "333", "UKW": "444", "CCC": "555"]
but no mater what I try, since i call the map function on an Array it seems impossible to convert the nature of the map function's result.
NOTE: The dictionary in string format is described as either having KEY:VALUE; format or VALUE; format, in which case the mapping function will add the "N/A" as being the key of the unnamed value.
Any help on this matter is greatly appreciated.
Your map produces an array of dictionaries. When you want to combine them into 1, that's a perfect job for reduce:
func + <K,V>(lhs: Dictionary<K,V>, rhs: Dictionary<K,V>) -> Dictionary<K,V> {
var result = Dictionary<K,V>()
for (key, value) in lhs {
result[key] = value
}
for (key, value) in rhs {
result[key] = value
}
return result
}
var str = "AAA:111;BBB:222;333;444;CCC:555"
var astr = str
.componentsSeparatedByString(";")
.reduce([String: String]()) {
aggregate, element in
var elements = element.componentsSeparatedByString(":")
if elements.count < 2 {
elements.insert("N/A", atIndex: 0)
}
return aggregate + [elements[0]:elements[1]]
}
print(astr)
Swift has no default operator to "combine" two Dictionaries so you have to define one. Note that the + here is not commutative: dictA + dictB != dictB + dictA. If a key exist in both dictionaries, the value from the second dictionary will be used.
This is a work for reduce:
let str = "AAA:111;BBB:222;333;444;CCC:555"
let keyValueStrings = str.componentsSeparatedByString(";")
let dictionary = keyValueStrings.reduce([String: String]()) {
aggregate, element in
var newAggregate = aggregate
let elements = element.componentsSeparatedByString(":")
let key = elements[0]
// replace nil with the value you want to use if there is no value
let value = (elements.count > 1) ? elements[1] : nil
newAggregate[key] = value
return newAggregate
}
print(dictionary)
You can also make aggregate mutable directly:
let dictionary = keyValueStrings.reduce([String: String]()) {
(var aggregate: [String: String], element: String) -> [String: String] in
let elements = element.componentsSeparatedByString(":")
let key = elements[0]
// replace nil with the value you want to use if there is no value
let value = (elements.count > 1) ? elements[1] : nil
aggregate[key] = value
return aggregate
}
This is a functional approach, but you can achieve the same using a for iteration.
The reason this is happening is because map can only return arrays. If you are using this method to parse your string, then you need to convert it to a dictionary after.
var newDict = [String:String]()
for x in astr {
for (i, j) in x {
newDict[i] = j
}
}
The current issue with your code is that map function iterates over array containing [["key:value"],["key:value"]..] and you separate it again. But it returns ["key":"value"] which you then add to your array.
Instead you can add elements[0]:elements[1] directly to a locally kept variable which will fix your problem. Something like
finalVariable[elements[0]] = elements[1]

How can I put each word of a string into an array in Swift?

Is it possible to put each word of a string into an array in Swift?
for instance:
var str = "Hello, Playground!"
to:
var arr = ["Hello","Playground"]
Thank you :)
edit/update:
Xcode 10.2 • Swift 5 or later
We can extend StringProtocol using collection split method
func split(maxSplits: Int = Int.max, omittingEmptySubsequences: Bool = true, whereSeparator isSeparator: (Character) throws -> Bool) rethrows -> [Self.SubSequence]
setting omittingEmptySubsequences to true and passing a closure as predicate. We can also take advantage of the new Character property isLetter to split the string.
extension StringProtocol {
var words: [SubSequence] {
return split { !$0.isLetter }
}
}
let sentence = "• Hello, Playground!"
let words = sentence.words // ["Hello", "Playground"]
Neither answer currently works with Swift 4, but the following can cover OP's issue & hopefully yours.
extension String {
var wordList: [String] {
return components(separatedBy: CharacterSet.alphanumerics.inverted).filter { !$0.isEmpty }
}
}
let string = "Hello, Playground!"
let stringArray = string.wordList
print(stringArray) // ["Hello", "Playground"]
And with a longer phrase with numbers and a double space:
let biggerString = "Hello, Playground! This is a very long sentence with 123 and other stuff in it"
let biggerStringArray = biggerString.wordList
print(biggerStringArray)
// ["Hello", "Playground", "This", "is", "a", "very", "long", "sentence", "with", "123", "and", "other", "stuff", "in", "it"]
That last solution (from Leo) will create empty elements in the array when there are multiple consecutive spaces in the string. It will also combine words separated by "-" and process end of line characters as words.
This one won't :
extension String
{
var wordList: [String]
{
return componentsSeparatedByCharactersInSet(NSCharacterSet.alphanumericCharacterSet().invertedSet).filter({$0 != ""})
}
}

Resources