I need to change values of a Swift array.
My first try was to just iterate through but this does not work as I only get a copy of each element and the changes do not affect the origin array.
Goal is to have a unique "index" in each array element.
myArray = [["index": 0], ["index":0], ["index":0], ["index":0]]
counter = 0
for item in myArray {
item["index"] = counter
counter += 1
}
My next attempt was using map but I don't know how to set an increasing value. I could set the $0["index"] = 1 but I need an increasing value.
In which way would this be possible using map?
myArray.map( { $0["index"] = ...? } )
Thanks for any help!
The counter in a for loop is a constant. To make it mutable, you could use :
for var item in myArray { ... }
But that won't be helpful here since we'd be mutating item and not the elements in myArray.
You could mutate the elements in myArray this way :
var myArray = [["index": 0], ["index":0], ["index":0], ["index":0]]
var counter = 0
for i in myArray.indices {
myArray[i]["index"] = counter
counter += 1
}
print(myArray) //[["index": 0], ["index": 1], ["index": 2], ["index": 3]]
The counter variable is not needed here :
for i in myArray.indices {
myArray[i]["index"] = i
}
A functional way of writing the above would be :
myArray.indices.forEach { myArray[$0]["index"] = $0 }
I found a simple way and would like to share it.
The key is the definition of myArray. It would success if it's in this way:
let myArray : [NSMutableDictionary] = [["firstDict":1, "otherKey":1], ["secondDict":2, "otherKey":1], ["lastDict":2, "otherKey":1]]
myArray.enumerated().forEach{$0.element["index"] = $0.offset}
print(myArray)
[{
firstDict = 1;
index = 0;
otherKey = 1;
}, {
index = 1;
otherKey = 1;
secondDict = 2;
}, {
index = 2;
lastDict = 2;
otherKey = 1;
}]
How about a more functional approach by creating a brand new array to store the modified dictionaries:
let myArray = [["index": 0], ["index":0], ["index":0], ["index":0]]
let myNewArray = myArray.enumerated().map { index, _ in ["index": index] }
Related
I want set elements of array concurrently,so I write code to test:
let Count = 1000
let SubRangeCount = 100
var ary = [Int](repeating: 0, count: Count)
let times = Count/SubRangeCount
let _ = DispatchQueue.global(qos: .userInitiated)
DispatchQueue.concurrentPerform(iterations: times){ idx in
for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
ary[i] = Int.random(in: 0...Int.max)
}
}
}
above code working great!
But when I change like this:
let Count = 10000
let SubRangeCount = 1000
It's crash!
In playground it complain "Fatal error: UnsafeMutablePointer.initialize overlapping range: file Swift/UnsafePointer.swift, line 832"
But you can see every range of array's assignments is NOT overlapping!
So how to fix it? Thanks!
Array is not thread safe on Swift so you need to synchronise access to it, for instance with objc_sync_enter and objc_sync_exit:
func synchronized<T : AnyObject, U>(_ obj: T, closure: () -> U) -> U {
objc_sync_enter(obj)
defer {
objc_sync_exit(obj)
}
return closure()
}
var arr = [Int](repeating: 0, count: 100_000)
let obj = arr as NSObject // Object to synchronise
DispatchQueue.concurrentPerform(iterations: 100_000){ index in
synchronized(obj) {
arr[index] = Int.random(in: 0...Int.max)
}
}
Here the array is concurrently mutated from multiple threads, which creates a race condition. To avoid this you have to perform the critical operation in a thread-safe way. You can take help from Grand Central Dispatch in the Apple platform - which lets us deal with threads using its much simpler queue-based abstractions.
let Count = 10000
let SubRangeCount = 1000
var ary = [Int](repeating: 0, count: Count)
let times = Count/SubRangeCount
let serialQueue = DispatchQueue(label: "serial.Queue")
DispatchQueue.concurrentPerform(iterations: times){ idx in
print(idx)
for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
serialQueue.async {
ary[i] = Int.random(in: 0...Int.max)
}
}
}
You can also use lock.
let Count = 10000
let SubRangeCount = 1000
var ary = [Int](repeating: 0, count: Count)
let lock = NSLock()
let times = Count/SubRangeCount
DispatchQueue.concurrentPerform(iterations: times){ idx in
print(idx)
for i in (idx * SubRangeCount)..<((idx+1) * SubRangeCount) {
lock.lock()
ary[i] = Int.random(in: 0...Int.max)
lock.unlock()
}
}
I found a workaround for it:
DispatchQueue.concurrentPerform(iterations: enumTimes){ idx in
var subAry = ary1[(idx * SubRangeCount)..<((idx+1) * SubRangeCount)]
for i in subAry.indices {
subAry[i] = Int.random(in: 0...Int.max)
}
}
It's no Crash, and fast 3x-10x than serialize assignments.
my issue is this in TypeScript (now latest is v3.1)
I have a array of numbers
let mainArray : Array<number> = [1,2,3,4];
I have to find subarray of [2,3], how can i do?
My actual workaround is converting both arrays in string (toString()) and using .includes (ES6) function, and it works but i think is not the best solution.
Thank you!
You can use filter for this
let mainArray : Array<number> = [1,2,3,4];
var findArry = [2, 3];
var subArray = mainArray.filter(function(val) {
return findArry.indexOf(val) != -1 ? true : false;
});
console.log(subArray);
Well its more algorithm problem then typescript problem. But this solution should work for checking if there is subarray which matched with searched array:
const toTuples = (n) => (item, index, originalArr) => {
const arr = [];
for(let i = 0; i < n; i++) {
arr.push(originalArr[index + i]);
}
return arr;
}
const arr = [1,2,3,4,2,3];
const search = [2, 3];
const mapped = arr.map(toTuples(search.length));
console.log(mapped.some((currArray) => currArray.every((item) => search.includes(item))));
input:
let arrayInt = [7,8,3,4,5,9,1,2,6]
output
let newArray = [1,2,3,4,5,6,7,8,9]
how to do that WITHOUT using .sort method that available in Swift? I just failed in programming test, so I want to know the answer :(
Hey look at this may help you, there are more then 1 possibilities:
https://www.cs.cmu.edu/~adamchik/15-121/lectures/Sorting%20Algorithms/sorting.html
There is an example:
https://gist.github.com/tmdvs/d8edeb9bf26f2f5c3e50
EDIT: Here you have an example:
var unsortedArray = [7,8,3,4,5,9,1,2,6]
for i in stride(from: unsortedArray.count-1, to: 0, by: -1) {
for j in 1...i {
if unsortedArray[j-1] > unsortedArray[j] {
let tmp = unsortedArray[j-1]
unsortedArray[j-1] = unsortedArray[j]
unsortedArray[j] = tmp
}
}
}
After that the unsortedArray is sorted.
Bubble Sort
var unsortedArray = [7,8,3,4,5,9,1,2,6]
for i in 0..<unsortedArray.count {
for j in 0..<unsortedArray.count{
var temp = 0
if unsortedArray[i] < unsortedArray[j] {
temp = unsortedArray[i]
unsortedArray[i] = unsortedArray[j]
unsortedArray[j] = temp
}
}
}
print(unsortedArray)
I want to create an array or dictionary with reduce() using another array. Normally I would use:
class Foo {
var number: Int
init(number: Int) {
self.number = number
}
}
let array1 = [Foo(number: 1), Foo(number: 1), Foo(number: 2)]
let array2: [Int] = array1.reduce([]) { $0 + [$1.number] }
println(array2)
[1, 1, 1]
But if I want to manipulate the initial value I'll first have to assign it to a new array, manipulate it and return that array:
let array2: [Int: [Int]] = array1.reduce([:]) {
var results = $0
results[$1.number] = (results[$1.number] ?? []) + [$1.number]
return results
}
println(array2)
[2: [2], 1: [1, 1]]
Is there a way to avoid having to create a new array and return it and directly use the initial value?
You can make parameters variable in the reduce() closure:
let array2: [Int: [Int]] = array1.reduce([:]) {
(var results, i) in
results[i.number] = (results[i.number] ?? []) + [i.number]
return results
}
Can anyone tell me how to compare two arrays and delete the common terms in ActionScript?
Eg:
Array1 = [2,4,6,8,10,12]
Array2 = [1,2,3,4,5,6,7,8,9,10,11]
Array1 - Array2 = [12]
If you use ActionLinq, it is very easy to do set mathematics like this:
var array1:Array = [2,4,6,8,10,12];
var array2:Array = [1,2,3,4,5,6,7,8,9,10,11];
var subtraction:Array = Enumerable.from(array1)
.except(Enumerable.from(array2))
.toArray();
You can filter using a custom function.
This is not an optimized way of filtering a difference of arrays, but it'll get the job done.
subtraction = Array1.filter(function(item:*, index:int, arr:Array){
var i:int;
var l:int;
l = Array2.length;
for ( i=0; i < l; i++ )
{
if ( Array2[i] == item )
{
return false;
}
}
return true;
});
If you wish to knock out all duplicates from an Array then I suggest that you use a Set to make the lookup speed as fast as possible:
const a : Array = [ 2, 3, 4 ];
const b : Array = [ 3, 4, 5 ];
// Create a Set for Array 'b' to provide a fast lookup table.
const setB : Object = {};
var prop : *;
for each (prop in b) {
setB[key] = true
};
// Find all values which only belong in Array 'a'.
const uniqueToA : Array = [];
for each (prop in a) {
if (setB[prop] === undefined) {
uniqueToA.push(prop);
}
}
If you find yourself doing a lot of work with collections then I would advise you invest in a Collections Framework such as AS3Commons Collections.