I'm new to programming so am probably missing something simple.
My aim is to call on a list from a result stored in a variable and pull a random entry from that List. The result 'categoryResult' is the correct List name but [random] is showing a single letter within the List name. When 'categoryResult' is replaced with hard code everything works as it should.
void getQuestion() async {
categoryResult = category[catNo];
final questions = await _firestore
.collection('questions')
.document(category[catNo])
.collection(categoryResult[random])
.document('question')
.get();
newQuestion = questions.data['$questionNumber'];
}
Related
Ive got a function named allAppointmentList to get Appointments from the server using a GET method in AppointmentProvider class.
In my MyAppointments class I have initialized 2 lists named as appointment and allAppointments as below,
class _MyAppointmentState extends State<MyAppointment> {
bool isLoading = true;
List<Appointment> allAppointments=[];
List<Appointment> appointments = [];
And in the init state I have assigned the data I get from the allAppointmentList method to the 2 lists mentioned above.
#override
void initState() {
super.initState();
_loadAppointments();
}
_loadAppointments() async {
final AppointmentProvider appointmentProvider =
Provider.of<AppointmentProvider>(context, listen: false);
await appointmentProvider.getAllAppointments();
setState(() {
isLoading = false;
appointments = appointmentProvider.allAppointmentList;
allAppointments = appointmentProvider.allAppointmentList;
});
}
when I change one list the other changes as well.For example,
if I clear the appointments list,allAppoitments list gets cleared as well.If I remove the element in the second index of the appointments list,the element in the second index of the allAppointments list gets removed as well.
How can I make these two list act independently ?
Your problem is probably that you think this creates new lists:
appointments = appointmentProvider.allAppointmentList;
allAppointments = appointmentProvider.allAppointmentList;
My guess is that appointmentProvider.allAppointmentList returns the same List instance every time which is a problem here since you are then just assigning the same List object to both appointments and allAppointments.
I am not sure if you also want copies of all the objects inside the lists but if you just want to have independent lists which then contains references to the same objects, the safest would just be to do:
appointments = appointmentProvider.allAppointmentList.toList();
allAppointments = appointmentProvider.allAppointmentList.toList();
This will create new lists which then contains the same objects from appointmentProvider.allAppointmentList. But you can then delete/add elements to each of these lists without this change also happening to the other lists.
appointments and allAppointments are currently just references to appointmentProvider.allAppointmentList. You can create new instances as follows:
appointments = [...appointmentProvider.allAppointmentList];
allAppointments = [...appointmentProvider.allAppointmentList];
This uses a list literal [] in combination with the spread operator ... to create a new list with the same elements. Note that the elements themselves are still references to their original instances and are not deep copies.
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]}
I want to have an immutable list, since I don't really need the mutability so it likely to just cause bugs. However, the list is a lateinit var declared at the class level.
I want to initially populate the list with values from a loop somewhat like this:
for (items in someOtherCollection) {
val itemToAdd = doSomeProcessingOnThisData()
list.add(itemToAdd)
}
However, since the list is immutable, I can't call add(). Is there a better way to init a list such as this without simply adding all the values to a second, mutable list and then assigning it to an immutable list?
My current solution is this, but it just seems inefficient:
val tmpList = mutableListOf<Data>()
foos.forEach() {
val itemToAdd = doSomeProcessing()
foos.add(itemToAdd)
}
this.list = tmpList
If you want to make a new list processing some data in another collection, try this:
this.list = someOtherCollection.map {
doSomeProcessing()
}
Give this a read for a better understanding: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html
partial void Query1_PreprocessQuery(string Filter1, ref IQueryable<Type> query)
{
//how can I loop through the query and add data to a custom list
}
Generally speaking, the _PreprocessQuery method is for defining the contents of the query and not doing anything with those contents (which would be Post processing). So a simple method might read:
partial void Query1_PreprocessQuery(string Filter1, ref IQueryable<Type> query)
{
query = query.Where(x => x.FilterColumn == Filter1);
}
This is happening on the server side so even if you did intercept the results, I think it would be tricky to get any list you created back to the client side.
Once the query results have been passed to the client screen, you can then loop through the query and use the contents however you like, for example using Screen Property methods like Query1_Loaded or Collection methods like Query1_Changed depending on what you're trying to achieve. Untested code, but something like this:
partial void Query1_Loaded(bool succeeded)
{
// Loop through the rows on the screen ...
foreach (IEntityObject rowData in this.Query1)
{
// Reference individual values like this ...
string FilterResult = rowData.Details.Properties["FilterColumn"].Value.ToString()
}
}
}
I have the following code which evaluates a SpEL expression using data values defined in a Map object.
// data map
Map dataMap = new HashMap();
dataMap.put("abc",1);
dataMap.put("def",2);
dataMap.put("xyz",1);
dataMap.put("qwerty",2);
// spel rule expression
String ruleExpression = "#abc+#def";
// Set evaluation context
StandardEvaluationContext stdContext = new StandardEvaluationContext();
stdContext.setVariables(map);
// Evaluate the SpEL expression
ExpressionParser parser = new SpelExpressionParser();
Object returnValue = parser.parseExpression(ruleExpression).getValue(stdContext);
// returnValue = 3 :-)
In the real world our map is populated based in a DB query result set and the 'ruleExpression' is only known at runtime. I have a new requirement to log the values defined in the 'ruleExpression' such that a string like this is generated
abc=1,def=2
A brute force approach might see us parsing the 'ruleExpression' string to identify fieldnames that start with '#' using regex but i could see how this could get messy as the complexity of the ruleExpression increases.
I'm wondering since the SpEl engine must identify the fields declared in the 'ruleExpression' during the parseExpress() phase is there a way for us to reuse this logic?
EDIT - I did come across the VariableScope private inner class on the org.springframework.expression.spel.ExpressionState class which seems to do what i want but alas the it's not accessible.
You can try overriding lookupVariable in StandardExpressionContext and adding your logging in there. Replacing your stdContext with the following will catch each variable as it is used:
StandardEvaluationContext stdContext = new StandardEvaluationContext() {
#Override
public Object lookupVariable(String name) {
Object value = super.lookupVariable(name);
//do logging here
System.out.println(name + "=" + value);
return value;
}
};
This outputs:
abc=1
def=2
This will only catch the values which are used from variables. Anything that comes from a bean or other object etc. will not go through lookupVariable. Neither will variable values which are never used (due to a conditional for instance).