How do I append values fo an observed array in RxSwift - arrays

Trying to grasp RxSwift and get stuck on a few things.
var observedData = BehaviorSubject.from([2, 3, 4, 5, 6])
.map({$0*3}).subscribe(onNext: {
print("HELLO", $0)
})
How do I append an extra value to the array, so that the subscription is triggered again?
I tried observedData.onNext and observedData.accept but they don't work.
I also would like to know the difference between
var observedData = BehaviorSubject.from([2, 3, 4, 5, 6])
and
var observedData2 = BehaviorSubject<[Int]>(value: [2, 3, 4, 5, 6])
I first assumed it was different ways of writing the same thing, but I can't use .map on observedData2

Along with the answer #EtienneJézéquel gave...
The public static func ObservableType.from(_:) function returns an Observable whereas the BehaviorSubject.init(value:) creates a BehaviorSubject which must then be converted to an Observable before you can map(_:) it.
Also, it might help to understand better when you realize you don't append to the array that is contained by the BehaviorSubject, instead you emit a new array using it. That's why Etienne's code first copies the current array out of the subject using value() throws and appends to the copy and then pushes the new array into the subject using onNext(_:).
Lastly, don't make subjects vars they should always be lets because you don't want to reseat them after setting up chains to them.

something like that should work :
let subject = BehaviorSubject<[Int]>(value: [2, 3, 4, 5, 6])
subject.asObservable().map({$0.map({$0*3})}).subscribe(onNext: { print("HELLO", $0) }).disposed(by: disposeBag)
if var value = try? subject.value() {
value.append(1)
subject.on(.next(value))
}

Related

Array methods using splice

I want to add 2 numbers at the beginning of array using splice method . can some one explain why the 2nd method gives me an empty array as output?.
const arrayold = [5, 6, 7, 8];
arrayold.splice(0, 0, 1, 2);
const arrayNew = arrayold;
console.log(arrayNew);
const arrayold = [5, 6, 7, 8];
const arrayNew = arrayold.splice(0, 0, 1, 2);
console.log(arrayNew);
Because it returns a list of deleted objects!
The actual modified thing is in the variable/s
Like it is in the first case, you decided not to do var o1=o2.splice( /*arguments*/ ); but var _new=_old instead.
You can read more at mdn about what splice modifies and what it returns!
splice() modifies the source array and returns an array of the removed items. Since you didn't ask to remove any items, you get an empty array back. It modifies the original array to insert your new items
const arrayold = [5, 6, 7, 8];
const arrayNew= arrayold.splice(0, 0, 1, 2);
console.log(arrayNew);
The splice method generally return the removed item from an array. So In your second sceanrio arrayold.splice(0,0,1,2) you are not removing any element as you have mentioned 0 that's why it is giving you empty array

Is there a way I could iterate over elements in Swift while using method names?

let x = [1, 2, 2, 3, 3, 3, 1].reversed()
for element in x.method_name() {
print(element)
}
This returns
Value of type 'ReversedCollection<[Int]>' has no member 'method_name'.
Why? How do I reference the method I have created and have it do the functions I need it to do?
However, if I use the below, the problem seems to disappear. I would just like to pass in an array and do let the function do all, i.e.:
let x = Array([1, 2, 2, 3, 3, 3, 1].reversed())
Just in case you don't fully understand the motivation behind this overload of reversed returning a ReversedCollection instead of an Array, a ReversedCollection is just a "reversed view" of your original array. It is not a reversed copy of the original array. This is to save time and space, like a "lazy" collection. See this post for more details.
This is why you need the Array(...) initialiser to turn the reversed collection back into an array. You are opting out of the laziness.
On the other hand, there is another overload of reversed that returns an Array directly. Normally this overload is not selected because it is defined in a less specific type - Sequence, as opposed to Array. You need to give enough information about the type to use this overload:
let x: [Int] = [1, 2, 2, 3, 3, 3, 1].reversed()

How to get a pointer (instead of a copy) to an array in Swift?

In Swift, assigning an array to a new variable actually makes of copy. For example (as in Apple doc for Array):
var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[1, 2, 3, 4, 5]"
How do I actually get a pointer to the same array, so modifying the elements is reflected in the same array? (The reason for this is I access in static instances of another class, e.g. "SomethingManager.sharedInstance.arrayList[aKey]" and I'll like to shorten it to an assigned pointer variable.)
(I'm interested to know how to do this in Swift 4 and 5. I don't see any existing question for Swift language.)
EDIT:
I'm providing my rationale for the need to have a pointer instead of a copy.
Say, I have the following code:
var childrenTasks = [Int64: [TaskRef]]()
defined in a class, which is accessed:
MyClass.singleton.parentTask[parentTaskID].childrenTask[taskRefID]
As you can see that the code to access childrenTask is very long. I'd like to have a pointer, just an illustration :-
var aPointerToChildrenTasks = MyClass.singleton.parentTask[parentTaskID].childrenTask[taskRefID] // I want a pointer, not a copy!
aPointerToChildrenTask.remove(at: anIndex) // if it is a pointer, I can manipulate the same set of values of the array
It will help make my code easier to read. I need a pointer to manipulate the same set of values so I use a "var". If it is only read-only, I can use a "let", but still it has performance penalty if I get a copy.
How do I get a pointer in Swift? Is this possible? (I know that in Kotlin it is possible as it is pass-by reference.)
EDIT: I see some suggestion that this question is a duplicate. No, it is not. Those other questions/answers are specifically focused on inout parameters. For my case, I just want a pointer to work in the same function/method.
Not a ‘pure’ Swift solution, but using NSArray will give you the reference semantics you desire.
NSArray is toll-free bridgeable to Array, so you can use plain as instead of as!
var numbers = [1, 2, 3, 4, 5]
var numbersCopy = numbers as NSArray
numbers[0] = 100
print(numbers)
[100, 2, 3, 4, 5]
print(numbersCopy as Array)
[1, 2, 3, 4, 5]
If you are modifying the 'copy' you will need to use a NSMutableArray.
Edit:
oops 🤭
I think I was confused by the naming of your variable numbersCopy. I see now that you want the 'copy' to share the same value as the original. By capturing the variable numbers in a block, and executing that block later, you can get the current value of numbers, and you don't need to use NSArray at all.
var numbers = [1, 2, 3, 4, 5]
var numbersCopy = {numbers}
numbers[0] = 100
print(numbers)
[100, 2, 3, 4, 5]
print(numbersCopy())
[100, 2, 3, 4, 5]
If it's just about convenience, consider making a utility function like this:
func withChildrenTasks(of parentTaskID: Int64, taskRefID: TaskRef, body: (inout [TaskRef]) -> ()) {
body(&MyClass.singleton.parentTask[parentTaskID].childrenTasks[taskRefID])
}
withChildrenTasks(of: parentTaskID, taskRefID: taskRefID) { tasks in
// do stuff with tasks
}
You can't create an "inout var", but you can always make a callback that accepts an inout parameter, so this is an easy workaround. I expect that the Swift compiler would be pretty good about optimizing it away.
If it's because you actually want to share the array reference, you will either need to wrap it in a reference type (class SharedArray<T> { var array = [T]() } might be enough for that purpose), or you could use NSMutableArray from Foundation.
Use a computed property:
var numbers = [1, 2, 3, 4, 5]
var numbersCopy: [Int] {
get { numbers }
set { numbers = newValue }
}
numbers[0] = 100
print(numbers)
// Prints "[100, 2, 3, 4, 5]"
print(numbersCopy)
// Prints "[100, 2, 3, 4, 5]"
numbersCopy[1] = 200
print(numbers)
// Prints "[100, 200, 3, 4, 5]"
print(numbersCopy)
// Prints "[100, 200, 3, 4, 5]"

Need to create an array of sets swift

I'm brand new to Swift, and it's been awhile since I've done any programming at all so please forgive me. I need some help on how to create an empty array that would contain a set of numbers.
What I'm trying to do is read two sets of numbers in from two different data files, and place them into two different data structures - in this case - arrays. I then want to loop through the array and determine if one group of numbers is a subset of the other. I have created the following code in the swift playground, and tested it and I know it can be done using pre-defined values in the code.
However, I can't seem to find anywhere online how to create an array of sets. I find all sorts of links that say when to use an array rather than a set and vice versa. When I try to declare an empty Array of type Set it gives me an error. I would appreciate anyone pointing me in the right direction. Here is the code that I typed into the playground that works.
var a: Set = [1,2]
var b: Set = [1,3]
var c: Set = [1,4]
var aa: Set = [1,4,23,29,50]
var bb: Set = [1,3,45,47,65]
var cc: Set = [7,9,24,45,55]
let combiArray = [a, b, c]
let resultsArray = [aa, bb, cc]
for i in 0...2 {
print (resultsArray[i],
combiArray[i],
combiArray[i].isSubset(of: resultsArray[i]))
}
Set is a generic type. When you say var a: Set = [1, 2], the compiler infers the necessary generic type parameter for you, making it equivalent to var a: Set<Int> = [1, 2]
To make an empty Array of Sets, you have to explicitly state what kind of Set you want, because the compiler can't infer it from the Set's contents. You're looking to make an empty Array<Set<Int>>, a.k.a. [Set<Int>].
Either:
let arrayOfSets: [Set<Int>] = []
or:
let arrayOfSets = [Set<Int>]() // preferred
Here's that reflected in your example:
let combiArray: [Set<Int>] = [ // TODO: What the heck is a "combi"?
[1, 2],
[1, 3],
[1, 4],
]
let results: [Set<Int>] = [
[1, 4, 23, 29, 50],
[1, 3, 45, 47, 65],
[7, 9, 24, 45, 55],
]
for (combi, result) in zip(combiArray, results) {
print("\(combi) \(combi.isSubset(of: result) ? "is" : "is not") a subset of \(result).")
}

Transferring one Integer from one array to another causes invalid array size

In my project, I have two arrays of Ints
In pseduocode;
var existingOrders:[ExistingOrder] ...
var completedOrders:[CompletedOrder] ..
protocol ValueProtocol {
var value: Int { get set }
}
class ExistingOrder: ValueProtocol {
var value: Int = 0
}
class CompletedOrder: ValueProtocol {
var value: Int = 0
}
Yes, I know that functionality is the same; but I'm needing it to be two classes for a reason that is outside the scope of this question.
One function I'm writing I need to transfer one order from Existing Order to Completed.
In my code I loop through all the values I want to transfer, then transfer them
for (index, item) in self.completedOrders.enumerated() {
item.value = Die.roll()
self.transfer(index: index, destination: .existingOrder)
}
The transfer function moves it from existingOrder -> completedOrder and vice versa.
The problem is this:
When it steps through the array shown above it'll pop an object during the transfer; and now the size of the array has changed and is no longer correct.
Visually stepping through it, it looks like this;
ie;
// stepping through the for-loop
existingOrders = [3,2]
transfer > index 0 (Integer value of 3) -> completed
existingOrders = [2]
transfer > index 1 .. crash; because the size of the array isn't correct any more.
So the for-loop is going through each item it needs to transfer, but because the transfer itself is amending the for-loop it changes the contents of said array and causes a crash.
The reason I use an index is because sometimes I want a specific item within the existing orders to be transferred.
I'm wondering how I can avoid this issue?
Thanks
Loop through your array in reverse order. That way, the earlier indices will still be valid as the later items are removed:
for (index, item) in self.completedOrders.enumerated().reversed() {
item.value = Die.roll()
self.transfer(index: index, destination: .existingOrder)
}
Here's an example of how this works with an array of numbers in which we remove the odds ones:
var numbers = Array(1...10) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var odds = [Int]()
for (index, number) in numbers.enumerated().reversed() {
if number % 2 == 1 {
odds.insert(number, at: 0)
numbers.remove(at: index)
}
}
print(numbers) // [2, 4, 6, 8, 10]
print(odds) // [1, 3, 5, 7, 9]

Resources