So I know I'm missing something obvious, however, after searching similar/related questions, I can't quite figure out what I'm doing wrong.
New to Kotlin, so probably something I'm not understanding properly.
Creating an ArrayList, as I need a growing list of items, starting with none. Think of it like an undo list. It'll grow to an unknown size. At some point, I'll reset it back to "empty" when needed.
Inside this list, I need an Array of Integers. These 3 values are a co-ordinate system - if it matters (ie x,y,z).
Everything I try, I keep ending up only being able to retrieve the final IntArray set added.
Using:
https://developer.android.com/training/kotlinplayground
fun main() {
// array list
var myList = arrayListOf<IntArray>()
// 3 item "test" array to populate array list with
var myArr = IntArray(3){0}
// setup Array list with 3 items
for ( b in 0..2 ) {
// fake/create a temp array with some simple values
for ( i in 0..2 ) { myArr[i] = 3+b+(3*i) }
// add it to the List
myList.add(b, myArr)
// confirm values
println ( "Added [" + myList.lastIndex +"] = " + myArr[0] +"-"+ myArr[1] +"-"+ myArr[2] )
}
// confirm size of Array List
println ( "size: " + myList.size )
// test pull the middle array from the ArrayList
// indices should be: 0, 1 and 2
var testArr = myList.get(1)
println ( "for idx 1: vals: " + testArr[0] +"-"+ testArr[1] +"-"+ testArr[2])
// test display all values for all arrays
myList.forEach {
println ( "Vals: " + it[0] +"-"+ it[1] +"-"+ it[2] )
}
// another method to do same ?
for ((index,value) in myList.withIndex()) {
println("index: $index ... " + value[0] +"-"+ value[1] +"-"+ value[2])
}
}
output is:
Added [0] = 3-6-9
Added [1] = 4-7-10
Added [2] = 5-8-11
size: 3
for idx 1: vals: 5-8-11
Vals: 5-8-11
Vals: 5-8-11
Vals: 5-8-11
index: 0 ... 5-8-11
index: 1 ... 5-8-11
index: 2 ... 5-8-11
Everything makes perfect sense up until the repeats of "5-8-11" .. what am I doing wrong?
I read your code, I think the problem is the IntArray you use, it is an object, every time you add it to the list, it is the same object. so In the end, it is always the same element.
please change the code to the following:
...
for ( b in 0..2 ) {
// fake/create a temp array with some simple values
var myArr = IntArray(3){0}
for ( i in 0..2 ) { myArr[i] = 3+b+(3*i) }
// add it to the List
myList.add(b, myArr)
// confirm values
println ( "Added [" + myList.lastIndex +"] = " + myArr[0] +"-"+ myArr[1] +"-"+ myArr[2] )
}
...
that should resolve your problem.
Here is the explanation of the reference object
As you work with objects, it's important to understand references.
A reference is an address that indicates where an object's variables and methods are stored.
You aren't using objects when you assign an object to a variable or pass an object to a method as an argument. You aren't even using copies of the objects. Instead, you're using references to those objects.
Here is the description about kotlin, it explains by image and content, you can read this.
The issue is that in:
for ( i in 0..2 ) { myArr[i] = 3+b+(3*i) }
you always modifying and adding the same object: myArr .
To fix, replace
for ( i in 0..2 ) { myArr[i] = 3+b+(3*i) }
with
val a = IntArray(3) { i -> 3+b+(3*i) }
and then add a:
myList.add(a)
Or, if populating the IntArray is as simple as in the example just:
myList.add(IntArray(3) { i -> 3+b+(3*i) })
The final code looks like this:
fun main() {
val myList = arrayListOf<IntArray>()
// setup Array list with 3 items
for ( b in 0..2 ) {
myList.add(IntArray(3) { i -> 3+b+(3*i) })
}
for ((index,value) in myList.withIndex()) {
println("index: $index ... " + value[0] +"-"+ value[1] +"-"+ value[2])
}
}
or even more concise (probably too much):
fun main() {
val myList = List(3) { b -> IntArray(3) { i -> 3 + b + (3 * i) } }
for ((index, value) in myList.withIndex()) {
println("index: $index ... " + value[0] + "-" + value[1] + "-" + value[2])
}
}
Creating an ArrayList, as I need a growing list of items, starting
with none. Think of it like an undo list. It'll grow to an unknown
size. At some point, I'll reset it back to "empty" when needed.
This sounds like you need a Stack. You could use a MutableList for this, or the ArrayDeque class. With size, addLast(element), clear, contains(element), isEmpty(), last() , and removeLast() you have everything at hand for manipulating something like an Undo list.
To construct it you would do:
val stack = ArrayDeque<IntArray>()
for (b in 0..2) {
val intArray = IntArray(3)
for (i in 0..2) {
intArray[i] = 3 + b + (3 * i)
}
stack.addLast(intArray)
}
stack.forEach { println(it.joinToString("-")) }
Output:
3-6-9
4-7-10
5-8-11
Related
I'm trying to sort an entire list according to one property. Afterwards I'd like to sort this list according to a second property, but in groups of 4. So, after sorting the list once, I want to look at the first 4 positions and sort only these 4 according to the second property - then move on to the next 4 positions and sort these again, and so on...
This is what I have so far:
class myElements {
int Position;
String text;
int Top;
int Left;
myElements(int Position, String text, int Top, int Left){
this.Position = Position;
this.text = text;
this.Top = Top;
this.Left = Left;
}
}
var FirstList = new List<myElements>();
var newList = new List<myElements>();
Adding Elements to my first list:
myElements Test = myElements(ElementNumber, text, Top, Left);
FirstList.add(Test);
Then sorting for the first time according to 'Top':
Comparator<myElements> TextComparator = (a, b) => a.Top.compareTo(b.Top);
FirstList.sort(TextComparator);
Here is where I'm stuck. I'm trying to sort the list again, but only in groups of 4 - this time according to 'Left':
for (int i = 0; i < FirstList.length; i += 4) {
Comparator<myElements> TextComparator2 = (a, b) =>
a.Left.compareTo(b.Left);
newList.addAll(FirstList.sublist(i, i + 3).sort(TextComparator2)); //this line does not work
}
I think I am stuck trying to access my sorted sublist: (FirstList.sublist(i, i + 4).sort(TextComparator2) . If I could add these to a new list, it should work.
However any other suggestions are more than welcome.
Thanks so much!
newList.addAll(FirstList.sublist(i, i + 3).sort(TextComparator2)); //this line does not work
Your code is almost correct. You have the right idea, but you ended up trying to do too much in one line of code.
Breaking it down a bit, your code is equivalent to:
var sublist = FirstList.sublist(i, i + 3);
newList.addAll(sublist.sort(...)); // Does not work
And that doesn't work because List.sort does not return a value. It mutates the list instead of returning a new list.
It would work if you instead did:
var sublist = FirstList.sublist(i, i + 3);
sublist.sort();
newList.addAll(sublist);
Also, List.sublist uses an exclusive end index. If you want to create sublists with 4 elements, you would need to use sublist(i, i + 4).
My client wants a list of every item with the name of the categories it belongs to in each appropriate column.
<cfscript>
arr = ArrayNew(1);
arr[1] = '';
arr[2] = 'category B';
stc["Item One"] = arr;
arr[1] = 'category A';
arr[2] = '';
stc["Item Two"] = arr;
arr[1] = 'category A';
arr[2] = 'category B';
stc["Item Three"] = arr;
writedump(stc);
for (element in stc) {
WriteOutput(element & '<br>');
// The next line produces:
// Object of type class java.lang.String cannot be used as an array
for (i=1; i<=ArrayLen(element); i+=1) {
}
}
</cfscript>
Q: How do I get to the arrays inside of each element?
In your example, you are using a for ... in loop to iterate through the keys of the struct, not the values. This can be a bit confusing, for the same syntax with an array will iterate through the elements.
In your code, you have placed the key string into element, which isn't the array. This is the reason why the error Object of type class java.lang.String cannot be used as an array is produced.
As RRK has answered, to access the value in the struct you need to use the syntax struct[keyOfItem].
//Loop keys in the struct
for (key in stc) {
writeOutput(key & '<br>');
//Loop items in the array
for(element in stc[key]){
writeOutput(element & '<br>');
}
}
You can access the arrays inside using [] representation.
stc[element] This will get you the array.
for (i=1; i<=ArrayLen(stc[element]); i+=1) {
writedump(stc[element][i]);
}
DEMO
I need to remove the first element from an array, that is present in a second array.
Looking through the std.algorithm package, I can get part way there with findAmong and remove.
But is there a way to combine these, so that I can both remove an element, and see which element was removed?
For example:
// array that will have elements removed
auto targetStrings = ["a", "b", "c"];
// holder for element that will be removed
string removedString;
// array to match against, to determine what should be removed
auto removeStrings = ["b", "a"];
auto r = findAmong(targetStrings, removeStrings);
if (r.count > 0) {
removedString = r[0];
targetStrings = targetStrings.remove!(c => c == removedString);
}
writeln(removedString);
writeln(targetStrings);
You can get the element's index by subtracting the length of the remaining range returned by findAmong from the length of the original range, and then just use remove with the index:
auto r = findAmong(targetStrings, removeStrings);
if (!r.empty)
{
removedString = r.front;
auto index = targetStrings.length - r.length;
targetStrings = targetStrings.remove(index);
}
Alternatively, get the index directly with countUntil:
auto index = targetStrings.countUntil!(s => removeStrings.canFind(s));
if (index >= 0)
{
removedString = targetStrings[index];
targetStrings = targetStrings.remove(index);
}
I have a list of items and for each item I am computing a value. Computing this value is a bit computationally intensive so I want to minimise it as much as possible.
The algorithm I need to implement is this:
I have a value X
For each item
a. compute the value for it, if it is < 0 ignore it completely
b. if (value > 0) && (value < X)
return pair (item, value)
Return all (item, value) pairs in a List (that have the value > 0), ideally sorted by value
To make it a bit clearer, step 3 only happens if none of the items have a value less than X. In step 2, when we encounter the first item that is less than X we should not compute the rest and just return that item (we can obviously return it in a Set() by itself to match the return type).
The code I have at the moment is as follows:
val itemValMap = items.foldLeft(Map[Item, Int)]()) {
(map : Map[Item, Int], key : Item) =>
val value = computeValue(item)
if ( value >= 0 ) //we filter out negative ones
map + (key -> value)
else
map
}
val bestItem = itemValMap.minBy(_._2)
if (bestItem._2 < bestX)
{
List(bestItem)
}
else
{
itemValMap.toList.sortBy(_._2)
}
However, what this code is doing is computing all the values in the list and choosing the best one, rather than stopping as a 'better' one is found. I suspect I have to use Streams in some way to achieve this?
OK, I'm not sure how your whole setup looks like, but I tried to prepare a minimal example that would mirror your situation.
Here it is then:
object StreamTest {
case class Item(value : Int)
def createItems() = List(Item(0),Item(3),Item(30),Item(8),Item(8),Item(4),Item(54),Item(-1),Item(23),Item(131))
def computeValue(i : Item) = { Thread.sleep(3000); i.value * 2 - 2 }
def process(minValue : Int)(items : Seq[Item]) = {
val stream = Stream(items: _*).map(item => item -> computeValue(item)).filter(tuple => tuple._2 >= 0)
stream.find(tuple => tuple._2 < minValue).map(List(_)).getOrElse(stream.sortBy(_._2).toList)
}
}
Each calculation takes 3 seconds. Now let's see how it works:
val items = StreamTest.createItems()
val result = StreamTest.process(2)(items)
result.foreach(r => println("Original: " + r._1 + " , calculated: " + r._2))
Gives:
[info] Running Main
Original: Item(3) , calculated: 4
Original: Item(4) , calculated: 6
Original: Item(8) , calculated: 14
Original: Item(8) , calculated: 14
Original: Item(23) , calculated: 44
Original: Item(30) , calculated: 58
Original: Item(54) , calculated: 106
Original: Item(131) , calculated: 260
[success] Total time: 31 s, completed 2013-11-21 15:57:54
Since there's no value smaller than 2, we got a list ordered by the calculated value. Notice that two pairs are missing, because calculated values are smaller than 0 and got filtered out.
OK, now let's try with a different minimum cut-off point:
val result = StreamTest.process(5)(items)
Which gives:
[info] Running Main
Original: Item(3) , calculated: 4
[success] Total time: 7 s, completed 2013-11-21 15:55:20
Good, it returned a list with only one item, the first value (second item in the original list) that was smaller than 'minimal' value and was not smaller than 0.
I hope that the example above is easily adaptable to your needs...
A simple way to avoid the computation of unneeded values is to make your collection lazy by using the view method:
val weigthedItems = items.view.map{ i => i -> computeValue(i) }.filter(_._2 >= 0 )
weigthedItems.find(_._2 < X).map(List(_)).getOrElse(weigthedItems.sortBy(_._2))
By example here is a test in the REPL:
scala> :paste
// Entering paste mode (ctrl-D to finish)
type Item = String
def computeValue( item: Item ): Int = {
println("Computing " + item)
item.toInt
}
val items = List[Item]("13", "1", "5", "-7", "12", "3", "-1", "15")
val X = 10
val weigthedItems = items.view.map{ i => i -> computeValue(i) }.filter(_._2 >= 0 )
weigthedItems.find(_._2 < X).map(List(_)).getOrElse(weigthedItems.sortBy(_._2))
// Exiting paste mode, now interpreting.
Computing 13
Computing 1
defined type alias Item
computeValue: (item: Item)Int
items: List[String] = List(13, 1, 5, -7, 12, 3, -1, 15)
X: Int = 10
weigthedItems: scala.collection.SeqView[(String, Int),Seq[_]] = SeqViewM(...)
res27: Seq[(String, Int)] = List((1,1))
As you can see computeValue was only called up to the first value < X (that is, up to 1)
I want to split List of user generic List into its small list with each 5 records.
Ex
I have List: u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15.
so must be split into
List1:u1,u2,u3,u4,u5
List2:u6,u7,u8,u9,u10
List3:u11,u12,u13,u14,u15
Any direct method available or need programing logic in c# ?
You can group on the index:
List<List<User>> lists =
list
.Select((u, i) => new { List = i / 5, User = u })
.GroupBy(g => g.List, g => g.User)
.Select(g => g.ToList())
.ToList();
You can also use Range to make a loop and get a part of the list for each iteration:
List<List<User>> lists =
Enumerable.Range(0, (list.Count + 4) / 5)
.Select(n => list.Skip(n * 5).Take(5).ToList())
.ToList();
You can Use Skip(count) and Take(count) methods.
// These are your objects, put here your init code
var list = Enumerable.Range(1, 20).ToList();
var lists = new List<int>[(list.Count + 4) / 5]; // The array of lists you wanted
for (int i = 0; i < lists.Length; i++)
{
lists[i] = list.Skip(i * 5).Take(5).ToList();
}
The (list.Count + 4) / 5 is a method to round UP the division (if I have 6 elements in list, I want two sublists)
If you really need a List of List...
var lists = new List<List<int>>((list.Count + 4) / 5);
for (int i = 0; i < lists.Capacity; i++)
{
lists.Add(list.Skip(i * 5).Take(5).ToList());
}
I think this might be more efficient since you're not doing groupings, orderings and such. This is just a single iteration over the dataset.
var splitList= new List<IEnumerable<User>>();
List<User> currentList = null;
int count = 0;
foreach(var user in users)
{
if (0 == count% 5)
{
currentList = new List<User>(5);
returnValue.Add(currentList);
}
currentList.Add(key);
count++;
}
return returnValue;