Reputation: 2571
Say I have this:
class NumWithSuccessor {
var num = 1
val successor
get() = num + 1
}
Now, if I want an array of num
s instead,
class NumsWithSuccessors {
var nums = Array<Int>(3){ 1 }
val successor
get() = /* What? */
}
My first guess is to use
get() = { Array<Int>(3){ nums[it] + 1 } }
But that would lead to creation of a new array every time I need to access a successor. Is there a simple, better way?
Practical Example:
// Need to go from this...
private val _dayWiseEventsList = // For internal use
MediatorLiveData<List<Event>>()
val dayWiseEventsList: LiveData<List<Event>> // For immutable, external observation
get() = _dayWiseEventsList
// ... to this
private val _dayWiseEventsListArray = // For internal use
Array<MediatorLiveData<List<Event>>>(DAYS) { MediatorLiveData() }
val dayWiseEventsListArray // For immutable, external observation
// Need an alternative for this
get() = Array<LiveData<List<Event>>>(DAYS) { _dayWiseEventsListArray[it] }
Upvotes: 0
Views: 1419
Reputation: 25874
You can lazily initialize it:
val successor by lazy { Array<Int>(3){ nums[it] + 1 } }
This will create the array only once when it is first accessed, then it will return the same array on subsequent accesses.
However note that this will not update successor
in case you modify nums
. If you want to update it you will need to set a customer setter for nums
and update successor
accordingly.
Like I explained in the comments, I would make all this immutable, for example:
data class NumsWithSuccessors(val nums: List<Int> = List(3){ 1 }) {
val successor by lazy { nums.map { it + 1 } }
}
Upvotes: 1
Reputation: 10006
class NumsWithSuccessors {
var nums: List<Int> = List(3){ 1 }
val successors: List<Int> = object: AbstractList<Int>() {
override val size get() = nums.size
override fun get(index: Int) = nums[index] + 1;
}
}
In the above example, successors
is a virtual List
that doesn't actually contain data. When you try to read an item from successors
, it simply looks at the underlying nums
list to calculate the value. The AbstractList
class deals with providing implementations for all the other list behaviour, based on the get
and size
implementations you supply.
This works with a List
, but not with an Array
. An array can't have custom behaviour; it's a primitive data type that just stores values. List
is an interface, the underlying behaviour of which can be modified at will.
Upvotes: 1
Reputation: 30755
successor
can't depend on nums
, has val
modifier and use cached array at the same time. The solution is to create a new list using map
function every time successor
property is accessed:
class NumWithSuccessor {
var nums = Array<Int>(3){ 1 }
val successor
get() = nums.map { it + 1 }
}
Upvotes: 0
Reputation: 1352
You can create a setter for nums, and set successor value inside it using map
operator. It prevents from creating a new array every time:
class NumsWithSuccessors {
var successor: Array<Int> = arrayOf()
var nums: Array<Int> = Array(3) { 1 }
set(value) {
field = value; successor = value.map { it + 1 }.toTypedArray()
}
Upvotes: 0