use a for loop to add element in to the java.util.ArrayList,but the list's address of the reference always changing - scala

I have a strange problem when I use a for loop to add element in to the java.util.ArrayList , but the list's address of the reference always changing
Here is the code:
var curntRow: Row = null
var startTime: lang.Long = null
//this is the list
var standTime: util.ArrayList[Row] = new util.ArrayList[Row]()
for (row <- usersCoorOrderByTime) {
if (curntRow == null) {
startTime = row.getAs[lang.Long](2)
} else if (!row.getAs[String](1).equals(curntRow.getAs[String](1))) {
//And I use the method list.add() right here
standTime.add(Row(row.getAs[String](0), row.getAs[String](1), row.getAs[DoubleType](4), row.getAs[DoubleType](5), curntRow.getAs[lang.Long](2) - startTime))
startTime = row.getAs[lang.Long](2)
}
curntRow = row
}
And please see the pic that I debug below:
addr is "7703"
Before get in the loop The list's addr is "7703"
When is get in the loop ,the address changes
change to "11268"
change to "11287"
The most strange things is when it end the loop, the address has changed back to where it was originally declared
change back to "7703"
finally I get an empty ArrayList

I found the error
the parameter of for loop is Dataframe, I should turn to Array or List then make for loop

Try using Mutable ArrayBuffer. Below is a simple example. I hope it helps.
val x = scala.collection.mutable.ArrayBuffer[String]()
x += "2"
x += "4"
println(x)

Related

Flutter/Dart global List variable changed in a foreach loop is unchanged after the loop

I have a list declared outside a for loop and then I assign some values to this list inside that for loop and its value is updated when printed inside the loop but when I print it after the loop, it gives me an empty list.
List<List<String>> chunkSizeCollection(List<String> followedList) {
int counter = 0;
int ongoingCounter = 0;
bool isLessThanTen = false;
List<List<String>> returnAbleChunkedList = [];
List<String> midList = [];
log("in followedlist");
followedList.forEach((element) {
if (counter == 0) {
int difference = followedList.length - ongoingCounter;
if (difference < 10) {
// log("in difference if: $difference");
isLessThanTen = true;
}
}
midList.add(element);
counter++;
ongoingCounter++;
if (counter == 10 || (isLessThanTen && ongoingCounter == followedList.length)) {
returnAbleChunkedList.add(midList);
log("returnAbleChunkedList in counter 10 after adding new val is: $returnAbleChunkedList");
//above log works properly and prints the updated list
midList.clear();
counter = 0;
}
});
//this log on the other hand, returns an empty list
log("returnAbleChunkedList: $returnAbleChunkedList before return");
return returnAbleChunkedList;
}
The output:
[log] returnAbleChunkedList in counter 10 after adding new val is: [[KQTuEPllbmRrlBNvYgZ7oUXwtA63, OZUZOE10IzT8quUFoZbNxZOynU32, fCYIlYemCvbLTc7SpNHw6fCHrcm1, CbcLrtDNOdYZyC23FzEehOrJbKx2, FFvvVHCpPGNKUiXPQD34QdoPqH32, Gk09y59vSVXa1HNhzYvc6Atqnt53, JDO356z8urYQvuktJmc6eNUYqSm2, YesvvNI43gUVYPMfqhG4uRO5t6K2]]
[log] returnAbleChunkedList: [[]] before return
In this line:
returnAbleChunkedList.add(midList);
you add a reference to midList to your output list. If your input is longer than 10, you'll end up adding more than one reference to midList to the output list (i.e. you might now have 2). Subsequently, you clear midList so you now have an output list that contains 2 references to a list that you've now cleared, so you end up with a list containing 2 empty lists.
If, instead, you changed this to:
returnAbleChunkedList.add(midList.toList());
you'd add a copy of midList to your output list and your end up with:
[[a, b, c, d, e, f, g, h, i, j], [k]]
as you expected.
The problem is this:
returnAbleChunkedList.add(midList);
midList.clear();
You add the object midlist to the list and then you clear it. So the object you added will be emptied. You have to create a copy or add the elements of the list.
returnAbleChunkedList.add(midList.toList());
// or
returnAbleChunkedList.add(List.of(midList));
// or
returnAbleChunkedList.add([...midList]);

how can this Repeated string concatenation function

using UnityEngine;
using System.Collections;
public class NewMonoBehaviour1 : MonoBehaviour
{
void ConcatExample(int[] intArray)
{
string line = intArray[0].ToString(); // the line is the var of the first in array
for(i =1;i <intArray.Length; i++) // the length is unknown ?
{
line += ", " + intArray[i].ToString(); //
}
return line;
//each time allocate new in original place
}
}
How can this function work ? the length of array is unknown , so how the for loop works ?Besides, this is void function but shouldn't return anythings right ,or is there any exceptional case ,finally,according to the unity manual, it is said that the function will keep producing a string but with new contents in the same place , resulting in consuming large memory space .Why ?thx
What makes you think that the Length should be unknown? It is a property that any array simply has
Gets the total number of elements in all the dimensions of the Array.
Of course it is not unknown the moment you call your method with an according parameter!
The return line; will not even compile since as you say the method is of type void so it can not return anything. It should probably be private string ConcatExample
Then what the unity manual (don't know where exactly you read this) means lies in
line += ", " + intArray[i].ToString();
under the hood every string in c# is an immutable char[]. So everytime you do a string concatenation via stringC = stringA + stringB what happens under the hood is basically something similar to
char[] stringC = new char[stringA.Length + stringB.Length];
for(var iA = 0; iA < stringA.Length; iA++)
{
stringC[i] = stringA[i];
}
for(var iB = 0; iB < stringB.Length; iB++)
{
stringC[iB + stringA.Length] = stringB[iB];
}
so whenever dealing with loops especially with large data it is strongly recommended to rather use a StringBuilder like
private string ConcatExample(int[] intArray)
{
var builder = new StringBuilder(intArray[0]);
for(i =1; i < intArray.Length; i++)
{
builder.Append(", ").Append(intArray[i].ToString());
}
return builder.ToString();
}
The length of the array will be the length of the array of ints you pass into the function as an argument.
say you pass it
Int[] ints = {1,2,3}
ConcatExample(ints); //the length of the array is now 3
add a debug.log() function to the ConcatExample method
void ConcatExample(int[] intArray)
{
string line = intArray[0].ToString();
for (int i = 1; i < intArray.Length; i++)
{
line += ", " + intArray[i].ToString(); //
Debug.Log(line);
}
}
debug.log would produce the following in the console
1, 2
1, 2, 3
and finally the return line; at the end would just result in an error because yes you are correct void returns nothing
This function CANNOT work, unless it gets the data it expects. A NULL passed to this function, for example, would generate a runtime null-reference exception. Passing a valid integer array, of length zero would generate an invalid index error on the first line.
You are correct, the function returns nothing, and appears pointless. In fact, I would have expected return line; to generate a complier error.
The string type appears "dynamic" meaning, it will indeed allocate more and more memory as needed. Technically, it is actually the string "+" operator, (a function that takes two strings as parameters) that is allocating this space. This function returns a new string, of the appropriate size. The garbage collector will DEallocate "old" strings when they are no longer referenced by any variables.

Sort/Order an Undetermined Number of Columns (LINQ\Entity Framework)

Need to sort/order a list of data based on an undetermined number of columns (1 or more).
What i'm trying to do is loop through the desired columns and add an OrderBy or ThenBy based on their number to the query'd list, but i'm unsuccessful...
Done this, but it doesn't compile:
var query = GetAllItems(); //returns a IQueriable list of items
//for each selected column
for (int i = 0; i < param.Columns.Length; i++)
{
if (i == 0)
{
query = query.OrderBy(x => x.GetType().GetProperty(param.Columns[i].Name));
}
else
{
//ERROR: IQueriable does not contain a definition for "ThenBy" and no extension method "ThenBy"...
query = query.ThenBy(x => x.GetType().GetProperty(param.Columns[i].Data));
}
}
How can i resolve this issue? Or any alternative to accomplish this requirement?
SOLUTION: #Dave-Kidder's solution is well thought and resolves the compile errors i had. Just one problem, OrderBy only executes (actually sorts the results) after a ToList() cast. This is an issue because i can't convert a ToList back to an IOrderedQueryable.
So, after some research i came across a solution that resolve all my issues.
Microsoft assembly for the .Net 4.0 Dynamic language functionality: https://github.com/kahanu/System.Linq.Dynamic
using System.Linq.Dynamic; //need to install this package
Updated Code:
var query = GetAllItems(); //returns a IQueriable list of items
List<string> orderByColumnList = new List<string>(); //list of columns to sort
for (int i = 0; i < param.Columns.Length; i++)
{
string column = param.Columns[i].Name;
string direction = param.Columns[i].Dir;
//ex.: "columnA ASC"
string orderByColumn = column + " " + direction;
//add column to list
orderByColumnList.Add(orderBy);
}
//convert list to comma delimited string
string orderBy = String.Join(",", orderByColumnList.ToArray());
//sort by all columns, yay! :-D
query.OrderBy(orderBy).ToList();
The problem is that ThenBy is not defined on IQueryable, but on the IOrderedQueryable interface (which is what IQueryable.OrderBy returns). So you need to define a new variable for the IOrderedQueryable in order to do subsequent ThenBy calls. I changed the original code a bit to use System.Data.DataTable (to get a similar structure to your "param" object). The code also assumes that there is at least one column in the DataTable.
// using System.Data.DataTable to provide similar object structure as OP
DataTable param = new DataTable();
IQueryable<DataTable> query = new List<DataTable>().AsQueryable();
// OrderBy returns IOrderedQueryable<TSource>, which is the interface that defines
// "ThenBy" so we need to assign it to a different variable if we wish to make subsequent
// calls to ThenBy
var orderedQuery = query.OrderBy(x => x.GetType().GetProperty(param.Columns[0].ColumnName));
//for each other selected column
for (int i = 1; i < param.Columns.Count; i++)
{
orderedQuery = orderedQuery.ThenBy(x => x.GetType().GetProperty(param.Columns[i].ColumnName));
}
you should write ThenBy after OrderBy like this:
query = query
.OrderBy(t=> // your condition)
.ThenBy(t=> // next condition);

Result not ready when used, works in debugger but not in runtime

In the following image you can see where i put the breakpoint and then debugged two step. You can also see that both assignments worked great they have the same count and are the same.
However if I do the following. Run the exact same call but only break on the third line directly then this happnes
set.QuestionSet.Questions should have count of 8 BEFORE the assigment, so it seems it's not properly assigned for some reason. I suspect this has something to do with how I fetch my data from DB.
Question and QuestionSet are normal POCOs and here is the code for the entire method.
public IEnumerable<QuestionSet> SearchAndFilterQuestionsAndSets(string searchString, int nrPerPage, int page, out int totalSearchCount)
{
searchString = searchString.ToLower();
List<QuestionSet> finalList = new List<QuestionSet>();
var result = ActiveContext.QuestionSets
.Select(x => new
{
QuestionSet = x,
Questions = x.Questions.Where(
y =>
y.Description.ToLower().Contains(searchString)
).OrderBy(
z => z.Description
)
})
.ToList();
foreach (var set in result)
{
//If our search matched the set itself we load all questions
if (set.QuestionSet.Name.ToLower().Contains(searchString))
{
//we dont bring empty sets
if (set.QuestionSet.Questions.Count() > 0)
{
set.QuestionSet.Questions = set.QuestionSet.Questions.ToList<Question>().OrderBy(x => x.Description).ToList<Question>();
finalList.Add(set.QuestionSet);
}
}
//We had one or more questions matching the search term
else if (set.Questions.Count() > 0)
{
var b = set.Questions.ToList<Question>();
set.QuestionSet.Questions = set.Questions.ToList<Question>();
finalList.Add(set.QuestionSet);
}
}
totalSearchCount = finalList.Count();
return finalList.Skip((page - 1) * nrPerPage).Take(nrPerPage);
}
UPDATE
If I do this instead in the failing else if
var a = new QuestionSet();
a.Id = set.QuestionSet.Id;
a.Name = set.QuestionSet.Name;
a.Questions = set.Questions.ToList<Question>();
finalList.Add(a);
Then it works, so the problem lies within the anonymous object, but why does it work when i step through with debugger and not otherwise?? call me puzzled.
Could be something to do with Late binding of anonymous types

Filter getElementsByTagName list by option values

I'm using getElementsByTagName to return all the select lists on a page - is it possible to then filter these based upon an option value, ie of the first or second item in the list?
The reason is that for reasons I won't go into here there are a block of select lists with number values (1,2,3,4,5 etc) and others which have text values (Blue and Black, Red and Black etc) and I only want the scripting I have to run on the ones with numerical values. I can't add a class to them which would more easily let me do this however I can be certain that the first option value in the list will be "1".
Therefore is there a way to filter the returned list of selects on the page by only those whose first option value is "1"?
I am pretty sure that there is a better solution, but for the moment you can try something like:
var allSelect = document.getElementsByTagName("select");
var result = filterBy(allSelect, 0/*0 == The first option*/, "1"/* 1 == the value of the first option*/);
function filterBy(allSelect, index, theValue) {
var result = [];
for (var i = 0; i < allSelect.length; i++) {
if(allSelect[i].options[index].value == theValue ) {
result.push(allSelect[i]);
}
}
return result;
}
I managed to get this working by wrapping a simple IF statement around the action to be performed (in this case, disabling options) as follows:
inputs = document.getElementsByTagName('select');
for (i = 0; i < inputs.length; i++) {
if (inputs[i].options[1].text == 1) {
// perform action required
}
}
No doubt there is a slicker or more economic way to do this but the main thing is it works for me.