Pushing elements of a multidimensional array into another one in Ruby - ruby-on-rails

I have these arrays of arrays :
array0 = [["1"], ["2"], ["3"],…]
array1 = [["a"], ["b"], ["c"],…]
array2 = [["pap"], ["pop"], ["pip"],…]
I want to push every element in every array, to the first array so the output should be:
output = [["1", "a", "pap"], ["2", "b", "pop"], ["3", "c" ,"pip"]]

First do flatten on each array to get single dimension array. Then use zip to get 2-dimension array each having 3-elements
array0.flatten.zip(array1.flatten, array2.flatten)
Shorter way of doing the same: (Solution given by #Ivaylo Strandjev)
array0.zip(array1, array2).map(&:flatten)

Try this:
array0.zip(array1).zip(array2).map(&:flatten)
Also you can do it with a single zip:
array0.zip(array1, array2).map(&:flatten)

Related

Sort dictionary of arrays by both key and values in Swift

I have a dictionary like this:
dict = {
"a": ["apple", "aeroplane", "ash"],
"c": ["cat", "car"],
"b": ["boy", "bit", "bee"]
}
I would like to sort it using swift and the result should be like this:
dict = {
"a": ["aeroplane", "apple", "ash"],
"b": ["bee", "bit", "boy"],
"c": ["car", "cat"]
}
Both the keys and the values in the array should be in alphabetical order. However, I can only successfully sort the keys using .keys.sorted() and I failed to sort the array in each of the dictionary values in alphabetical order.
First of all I just want to remark that it's a bit redundant to sort the keys of a dictionary because you check values associated with a given key, not where the value is, it makes no sense to order them.
Second about sorting the arrays inside the dictionary it's pretty easy, first you need to iterate over the dictionary using for each, then since the arrays are immutable after you call .sorted() you assign the result to the key associated with the value you just received.
var dict : [String:[String]] = [
"a" : ["apple", "aeroplane", "ash"],
"c" : ["cat", "car"],
"b" : ["boy", "bit", "bee"]
]
// sort arrays inside an item of the dictionary
for (key,value) in dict {
dict[key] = value.sorted()
}
print(dict)

Will appending array's object in array will maintain object sort order every time?

I'm doing some operations like sorting, filter and grouped by some attributes of arrays object.
I'm adding objects of a filtered array in to another array like:
arrGroup.append(contentsOf: filteredArray)
My question is: will all of the objects maintain the same sorted order in the array every time, with 100% certainty?
Logically, will it add the object like
for object in filteredArray {
arrGroup.append(object)
}
or
for index in 0...filteredArray.count {
let object = filteredArray[index]
arrGroup.append(object)
}
For me, all are same, just difference in CPU cycle at run time. But my friend says that I should go with last option. Technically I'm getting same result for all three every time I debug my code.
Your suggestion please.
Yes, when you add an Array to another Array it will maintain the order as it is.
But yes if you are using Set then you might not get same order as it is not ordered collection but Array is ordered collection which maintains it's ordering until you changes it manually.
here is the code example :
var arr1 = ["1", "2" , "3"] // Print arr1 : ["1", "2", "3"]
let arr2 = ["4", "5" , "6"] // Print arr2 : ["4", "5", "6"]
arr1.append(contentsOf: arr2) // Print arr1 : ["1", "2", "3", "4", "5", "6"]
Array preserves whatever ordering you give it.
Array.append(contentsOf:) appends all items of the second array to the end of the first array, in order. Here's roughly what that algorithm would look like:
extension Array {
mutating func myAppend(contentsOf other: [Element]) {
reserveCapacity(self.count + other.count)
for element in other {
self.append(element)
}
}
}
Techniques for iterating an array
If you only need the elements
The preferred method
The preferred way to iterate the items of a Sequence is to use a typical for-in loop:
for element in array { // most preferred!
// use the element
}
The discouraged method
for i in 0 ..< array.count {
let element = array[i] // Avoid this!
// use the element
}
I highly advise against this technique. The reason is because it's very easy to fall victim to an off-by-one-error. In fact, your very own example has it!
for index in 0...filteredArray.count {
let object = filteredArray[index] // when index is filteredArray.count ... 💣
arrGroup.append(object)
}
Don't use this! Any array of n elements has indices 0 ..< n, not 0 ... n. Attempting to access array[array.count] will crash your program.
Another valid but discouraged method
for i in array.indices {
let element = array[i] // Avoid this!
// use the element
}
If you only need the indices
for i in array.indices {
// use the index i
}
If you need both the indices and the elements
for (i, element) in array.enumerated() {
// use the index i and the element.
}
The 2 for loops you have above are doing the same thing in terms of they will iterate from object #0 to the last object.
The first one is called fast enumeration and hence faster and more effective than the second.
And to answer your question. Yes the order will remain the same.

Append an array of strings to a string in Swift

I have an array of strings for one variable, and a string as another variable. I'd like to append all of the strings in the collection to the single string.
So for example I have:
var s = String()
//have the CSV writer create all the columns needed as an array of strings
let arrayOfStrings: [String] = csvReport.map{GenerateRow($0)}
// now that we have all the strings, append each one
arrayOfStrings.map(s.stringByAppendingString({$0}))
the line above fails. I've tried every combination I can think of, but at the end of the day, I can't get it unless I just create a for loop to iterate through the entire collection, arrayOfStrings, and add it one by one. I feel like I can achieve this the same way using map or some other function.
Any help?
Thanks!
You can use joined(separator:):
let stringArray = ["Hello", "World"]
let sentence = stringArray.joined(separator: " ") // "Hello World"
You could convert your array to string using joinWithSeparator(String)
here is an example
var array = ["1", "2", "3"]
let stringRepresentation = array.joinWithSeparator("-") // "1-2-3"
source: [ How do I convert a Swift Array to a String? ]
There are at least two options here. The most semantic choice is likely joinWithSeparator on the [String] object. This concatenates every string in the array, placing the separator provided as a parameter between each string.
let result = ["a", "b", "c", "d"].joinWithSeparator("")
An alternative is to use a functional reduce and the + function operator which concatenates strings. This may be preferred if you want to do additional logic as part of the combine. Both example code produce the same result.
let result = ["a", "b", "c", "d"].reduce("", combine: +)
It's also worth noting the second options is transferrable to any type that can be added, whereas the first only works with a sequence of strings, as it is defined on a protocol extension of SequenceType where Generator.Element == String.

How to sort array based on another arrays position?

I have a tableView with its style being Right Detail. I therefore have 2 arrays, one is for the textLabels data, and the other is for detailTextLabel.
There will be 2 "sort by" options. One will be sort by the textLabels data, and the second will sort by the detailTextlabels data. So when I sort the first array (textLabels array), the second array (detailTextLables array) will also have to get sorted based on the firstarray`.
I know how to sort arrays, but how can I sort one array based on another?
Here's how I sorted the array: (it's an array of Dates.
firstArray.sort({ (a, b) -> Bool in
a.earlierDate(b) == a
})
First, why not have two arrays? Because you only have one array of UITableViewCells and you want to keep all the data associated with a particular table view cell together. And it makes the need to try to coordinate the sorting of multiple arrays (what you are asking to do) unnecessary.
But if you really want to do that:
var array1 = ["1", "3", "2"]
var array2 = ["One", "Three", "Two"]
let sortedFoo = zip(array1, array2).sort { $0.0 < $1.0 }
array1 = sortedFoo.map { $0.0 }
array2 = sortedFoo.map { $0.1 }
The idea with the above code is that it combines the two arrays into one array of tuples, and then sorts them based on the elements in the first array, then breaks that single array back out into two separate arrays.
In other words, since you have to combine the two arrays into one to do the sort anyway, you might as well make them in a single array in the first place. :-)
It's a bit messy, but you can use enumerate to work with indices and elements at the same time:
array1.enumerate().sort {
return $0.element < $1.element
}.map {$0.element}
array1.enumerate().sort {
return array2[$0.index] < array2[$1.index]
}.map {$0.element}
But it's really much simpler/easier with one array.
struct Item {
let prop1: Int
let prop2: String
}
var array = [
Item(prop1: 1, prop2: "c"),
Item(prop1: 2, prop2: "b"),
Item(prop1: 3, prop2: "a")
]
array.sort { $0.prop1 < $1.prop1 }
array.sort { $0.prop2 < $1.prop2 }
How about using using positionOf on the sorted array to find the corresponding index in the I sorted array?

Immutable/Mutable Collections in Swift

I was referring to Apple's Swift programming guide for understanding creation of Mutable/ immutable objects(Array, Dictionary, Sets, Data) in Swift language. But I could't understand how to create a immutable collections in Swift.
I would like to see the equivalents in Swift for the following in Objective-C
Immutable Array
NSArray *imArray = [[NSArray alloc]initWithObjects:#"First",#"Second",#"Third",nil];
Mutable Array
NSMutableArray *mArray = [[NSMutableArray alloc]initWithObjects:#"First",#"Second",#"Third",nil];
[mArray addObject:#"Fourth"];
Immutable Dictionary
NSDictionary *imDictionary = [[NSDictionary alloc] initWithObjectsAndKeys:#"Value1", #"Key1", #"Value2", #"Key2", nil];
Mutable Dictionary
NSMutableDictionary *mDictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:#"Value1", #"Key1", #"Value2", #"Key2", nil];
[mDictionary setObject:#"Value3" forKey:#"Key3"];
Arrays
Create immutable array
First way:
let array = NSArray(array: ["First","Second","Third"])
Second way:
let array = ["First","Second","Third"]
Create mutable array
var array = ["First","Second","Third"]
Append object to array
array.append("Forth")
Dictionaries
Create immutable dictionary
let dictionary = ["Item 1": "description", "Item 2": "description"]
Create mutable dictionary
var dictionary = ["Item 1": "description", "Item 2": "description"]
Append new pair to dictionary
dictionary["Item 3"] = "description"
More information on Apple Developer
Swift does not have any drop in replacement for NSArray or the other collection classes in Objective-C.
There are array and dictionary classes, but it should be noted these are "value" types, compared to NSArray and NSDictionary which are "object" types.
The difference is subtle but can be very important to avoid edge case bugs.
In swift, you create an "immutable" array with:
let hello = ["a", "b", "c"]
And a "mutable" array with:
var hello = ["a", "b", "c"]
Mutable arrays can be modified just like NSMutableArray:
var myArray = ["a", "b", "c"]
myArray.append("d") // ["a", "b", "c", "d"]
However you can't pass a mutable array to a function:
var myArray = ["a", "b", "c"]
func addToArray(myArray: [String]) {
myArray.append("d") // compile error
}
But the above code does work with an NSMutableArray:
var myArray = ["a", "b", "c"] as NSMutableArray
func addToArray(myArray: NSMutableArray) {
myArray.addObject("d")
}
addToArray(myArray)
myArray // ["a", "b", "c", "d"]
You can achieve NSMutableArray's behaviour by using an inout method parameter:
var myArray = ["a", "b", "c"]
func addToArray(inout myArray: [String]) {
myArray.append("d")
}
addToArray(&myArray)
myArray // ["a", "b", "c", "d"]
Re-wrote this answer 2015-08-10 to reflect the current Swift behaviour.
There is only one Array and one Dictionary type in Swift. The mutability depends on how you construct it:
var mutableArray = [1,2,3]
let immutableArray = [1,2,3]
i.e. if you create an assign to a variable it is mutable, whereas if you create an assign to constant it is not.
WARNING: Immutable arrays are not entirely immutable! You can still change their contents, just not their overall length!
Just declare your (any)object or variable with
'let' key word -> for "constan/Immutable" array, dictionary, variable, object..etc.
and
'var' key word -> for "Mutable" array, dictionary, variable, object..etc.
For more deeply information
“Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places."
var myVariable = 42
myVariable = 50
let myConstant = 42
Read “The Swift Programming Language.”
If you want to work with Array (Swift) as with NSArray, you can use a simple bridge function. Example:
var arr1 : Array = []
arr1.bridgeToObjectiveC().count
It works the same for let.
From Apple's own docs:
Mutability of Collections
If you create an array, a set, or a dictionary and assign it to a
variable, the collection that is created will be mutable. This means
that you can change (or mutate) the collection after it is created by
adding, removing, or changing items in the collection. Conversely, if
you assign an array, a set, or a dictionary to a constant, that
collection is immutable, and its size and contents cannot be changed.
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html#//apple_ref/doc/uid/TP40014097-CH8-ID105
Other uses of immutable/mutable collections depend on why you want them to be mutable/immutable. Collections are value types in Swift, which means their contents is copied when they are assigned to another value, or passed to another function/method. Therefore, you do not need to worry about whether a receiving method function might change the original array. Therefore you don't need to ensure to return an immutable collection if your class is holding a mutable collection, for instance.
Swift Mutable/Immutable collection
[Unmodifiable and Immutable]
Swift's array can be muted
[let vs var, Value vs Reference Type]
Immutable collection[About] - is a collection structure of which can not be changed. It means that you can not add, remove, modify after creation
let + struct(like Array, Set, Dictionary) is more suitable to be immutable
There are some classes(e.g. NSArray) which doesn't provide an interface to change the inner state
but
class A {
var value = "a"
}
func testMutability() {
//given
let a = A()
let immutableArr1 = NSArray(array: [a])
let immutableArr2 = [a]
//when
a.value = "aa"
//then
XCTAssertEqual("aa", (immutableArr1[0] as! A).value)
XCTAssertEqual("aa", immutableArr2[0].value)
}
It would rather is unmodifiable array

Resources