How does list mapping in dart actually work? - list

I am coming from a javascript background, and in javascript if i had an array with elements [1,2,3] I can map through this array and perform a function on each iteration as so:
[1,2,3].map((i) => {
console.log(i);
return;
})
and i get
1
2
3
Trying same in dart
void main() {
[1, 2, 3].map((i) {
print(i);
return;
});
}
No output is printed, what am I missing?

JavaScript is different from Dart.
According to the documentation, the map method on an Iterable is meant to
return a new lazy Iterable with elements that are created by calling f on each element of this Iterable in iteration order.
In other words, the function in the map method isn't called until it is needed because it is lazily invoked. It will not return anything until something asks for what it is supposed to return. As long as the returned Iterable is not iterated over, the supplied function f will not be invoked.
Try in dartpad.dev
void main() {
var arr = [1, 2, 3];
var arr2 = arr.map((item)=> {
item * 2
});
print ('$arr2');
}
In the example above, the function in the map method of arr is called/invoked because it is requested for by $arr2 in the print function. Because of this, it runs the code inside it and the parameter in the print method gets printed out
Try
print([1, 2, 3].map((i) {
print(i);
return;
}));
You'll see that you get your desired result, because the function in the map method was invoked by the print method.
Since the method is lazy, it will not be invoked until it is requested. Adding a map method to an array doesn't invoke it. You've got to require what it returns for the function in the map method to be invoked.

Related

Getting a List from Coroutines

I try to make a method that would get a list of movies from database using coroutine and would return me that list.
But as you know coroutine returns Deferred, not a list, so I have a problem here.
suspend fun getMovieList(): List<MovieLocalModel>{
val list = viewModelScope.async {
dbRepository.getMovie().toList()
}
return list
}
How can I convert Deferred List<MovieLocalModel to List<MovieLocalModel?
Or is there a method to get a list from LiveData?
To get an object from Deffered you can use await method:
suspend fun getMovieList(): List<MovieLocalModel>{
val list = viewModelScope.async {
dbRepository.getMovie().toList()
}
return list.await()
}
If you use LiveData you can get an object using value property:
val list = livaDataObj.value
If you don't have a reason this fetch needs to specifically be done in the viewModelScope, which is likely the case since it is only fetching something (not saving something), you can simplify this by calling the function directly.
suspend fun getMovieList(): List<MovieLocalModel> =
dbRepository.getMovie().toList()

Adding to list from hashmap key kotlin

I'm practicing leetcode problems to perfect my kotlin syntax and am wondering why this code doesn't work. My question specifically is why doesn't my courses hashmap populate with this code.
Prerequisites is an array in this form [[0,1][0,3][4,5][6,7]] and if I print my variables for pre and post they print what I expect
But I'm trying to turn courses into an adjacency matrix like this {0: [1,3], 4: [5], 6: [7]}
and instead it just prints an empty set every time
class Solution {
fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
val courses = HashMap<Int, MutableList<Int>>().withDefault{ mutableListOf<Int>() }
for ((pre, post) in prerequisites){
courses[pre]?.add(post)
}
print(courses)
return false
}
}
stdout: {}
[] does not give you the default value
From the docs of withDefault:
This implicit default value is used when the original map doesn't contain a value for the key specified and a value is obtained with Map.getValue function
If you want to get the default value, you need to use getValue instead of the index operator.
Using the index operator, you would just get null and because of the the null-safe operator, the add operation would not even be executed.
If you take a look at the relevant source code, you can see that the funxtionality get is not changed when using .withDefault but only getOrImplicitDefault returns the default value.
Getting the default does not set anything
Furthermore, when accessing courses.getValue(pre) in the loop, the Map will be empty. Because of the withDefault, it will return a MutableList where you can add elements but getting such a list and adding elements to it will not add the list to the Map. Reading and accessing an element does not insert it.
Simple solution
If you want to make sure the element is present in the Map, you can use courses[pre]=course.getValue(pre) before reading courses[pre]?:
class Solution {
fun canFinish(numCourses: Int, prerequisites: Array<IntArray>): Boolean {
val courses = HashMap<Int, MutableList<Int>>().withDefault{ mutableListOf<Int>() }
for ((pre, post) in prerequisites){
courses[pre] = courses.getValue(pre)
courses[pre]?.add(post)
}
print(courses)
return false
}
}
If the entry is set already, it will be set to itself (no change) and if it isn't set, it will be set to the default value (empty list).
dan1st's answer covers it - your default list is just returned, not put and returned, so it's not part of the map - but here's a different take to get that functionality:
val courses = HashMap<Int, MutableList<Int>>().run {
withDefault{ key ->
mutableListOf<Int>().also { put(key, it) }
}
}
So basically using the withDefault wrapper, using run so the map is this in the default value function, so you can add your list to the map before returning it. Then when you call courses.getValue(69) you'll get back a list that's already been inserted into the map
If you like, there's also a function that'll do this grouping for you, groupBy
val nums = arrayOf(
intArrayOf(0,1),
intArrayOf(0,3),
intArrayOf(4,5),
intArrayOf(6,7)
)
val groups = nums.groupBy(keySelector = { it[0] }, valueTransform = { it[1] })
println(groups)
>> {0=[1, 3], 4=[5], 6=[7]}

Swift3 - how to call class or struct functions by name

As I come from a JS background this is how I'd call a function by name stored in a variable:
var obj = {
foobar: function(param) {
// do something
}
};
var key = "foobar";
obj[key](123);
Now I would like to recreate this in Swift, for example:
struct obj = {
func foobar(param) {
// do something
}
}
let key:String = "foobar"
obj[key](123)
The above code unfortunately gives Type 'obj.Type' has no subscript members
Is there any way to call functions by names in a Struct, Class or a Dictionary (if it's even possible to store functions in Dicts?)
EDIT - MORE CONTEXT:
I have a user-supplied array of things say:
let arr = ["apples", "oranges", "pears"]
but this array can be as long as 20 items. Based on each item of the array I need to perform certain action. So I iterate over the array:
for (key, _) in arr {
if (key == "apples") {
handleApples()
}
if (key == "oranges") {
handleOranges()
}
// and so on...
}
Sure, I can have a function with a simple switch that would consist of 20 cases but that's far from ideal. What if my array grows to say 100 items?
I was hoping to achieve something similar to this:
for (key, _) in arr {
myClass[key]()
}
Is there any way to call functions by names in a Struct, Class or a Dictionary (if it's even possible to store functions in Dicts?)
Yes you can store a function into a dictionary
Let's define a function type
typealias FuncType = () -> ()
and 2 functions
func func0() {
print("Apples")
}
func func1() {
print("Oranges")
}
Now we can create a dictionary where the key is String and the value is FuncType
let dict : [String:FuncType] = [
"Apples" : func0,
"Oranges" : func1
]
And of course we can invoke a function stored into the dictionary
dict["Apples"]?() // prints "Apples"
I think this might be what you're looking for:
var obj: [String: Int] = {
// do something, like call foobar(param) that's defined outside of the variable
// or just manipulate data directly in here
return ["foobar": 123]
// or whatever dictionary you want that matches the type you defined for obj
}()
Kind of tough to give you a better answer without you posting the kind of output or behavior you're looking for.

Its fine to create a list that holds multiple variable types?

Generally speaking, its fine to create a list that holds multiple variable types?
For example
list = [0,"hello",True,0.25,[0,5]]
Im not asking IF i can do this (because for example you can in python), Im just asking if it is considered a bad (or messy) thing to do or not.
Technically, you could create a list of Object to store all of that. How would you know what was in each position? We are using a Hashtable to store multiple data types, but we are also storing keys, so we know what to expect when we retrieve it.
Here's an example in a C# console application:
static void Main(string[] args)
{
object[] list = { 0, "hello", true, 0.25, (new object[]{ 0, 5 }) };
foreach (var item in list)
{
Console.WriteLine(item.GetType().ToString() + ": " + item.ToString());
}
Console.ReadKey();
}

Ability to pass array to mocked method call

I have a method that i want to mock that takes an array as a argument. In a real call, the method would modify this array and the resultant array would be use further along in code.
What i tried to do was pass in array to the mocked method call, that had values that would be valid when the array is used again. However what i find is when the call is being made to the mocked method it doesn't use the array i have specfied when setting up the mock, instead using the original array, Is there a way around this problem.
e.g
public interface ITest
{
int Do(int[] values);
}
public void MyTest
{
var testMock = new Mock<ITest>();
int[] returnArray = new int[] {1,2,3};
testMock.Setup(x => x.Do(returnArray)).Returns(0);
MyTestObject obj = new MyTestObject();
obj.TestFunction(testMock.Object);
}
public class MyTestObject
{
.....
public void TestFunction(ITest value)
{
int [] array = new int[3];
value.Do(array);
if (array[0] == 1)
This is where my test falls down as array is still the null array declared two lines above and not the array i specified in the mocked method call. Hope this explains what i am trying to achieve and if so is there anyway of doing it. Would also be open to using RhinoMocks as well if it could be done that way.
Thank in advance,
Kev
The only thing you have done here is to set up an expectation that your Do method will be called with returnArray as parameter, and that it will return 0 as the result. What you want to do is to
create a strict mock to better see what is being executed
setup a call that expects your initial array, and then runs a delegate to set the values to 1, 2, 3
using Rhino Mock this would look like this (using moq it will be equivalent):
private delegate int DoDelegate(int[] values);
[Test]
public void MyTest()
{
var testMock = MockRepository.GenerateStrictMock<ITest>();
testMock.Expect(x => x.Do(null))
.IgnoreArguments()
.Do(new DoDelegate(delegate(int[] values)
{
values[0] = 1;
values[1] = 2;
values[2] = 3;
return 0;
}));
//Execution (use your real object here obviously
int[] array = new int[3];
testMock.Do(array);
Assert.AreEqual(1, array[0]);
}