How to use MutableList to remove with kotlin call java? - java

I have a MutableList with generic with Int, like MutableList.
I wonder how to use kotlin call java method remove(int position) and remove(Integer object) correctly?
public void remove(int position) {
if (this.list != null && this.list.size() > position) {
this.list.remove(position);
notifyDataSetChanged();
}
}
public void remove(T t) {
if (t != null && this.list != null && !this.list.isEmpty()) {
boolean removed = false;
try {
removed = this.list.remove(t);
} catch (Exception e) {
e.printStackTrace();
}
if (removed) {
notifyDataSetChanged();
}
}
}

There are overall 4 methods for removing items in kotlin.collections.MutableList as of Kotlin 1.2.30:
remove - used to remove element once. Calls to this method are compiled to calls to the Java method List.remove(Object o).
removeAt - used to remove at a certain position. Calls to this method are compiled to calls to the Java method List.remove(int index).
removeAll - used to remove a collection, each element multiple times
removeIf - remove using a predicate, each element multiple times
Below is an example of how you can use each method. In the comments you can find what each method would print to the console and a brief explanation of what it does:
fun main(args: Array<String>) {
val l: MutableList<Int> = mutableListOf<Int>(1, 2, 3, 3, 4, 5, 6, 7, 1, 1, 1)
println(l.remove(1)) // true
println(l) // [2, 3, 3, 4, 5, 6, 7, 1, 1, 1] - removes first element and stops
println(l.removeAt(0)) // 2 - removes exactly on a specific position
println(l) // [3, 3, 4, 5, 6, 7, 1, 1, 1]
try {
println(l.removeAt(10000))
} catch(e: IndexOutOfBoundsException) {
println(e) // java.lang.IndexOutOfBoundsException: Index: 10000, Size: 9
}
println(l.removeAll(listOf(3, 4, 5))) // true
println(l) // [6, 7, 1, 1, 1] - removes elements in list multiple times, 3 removed multiple times
println(l.removeIf { it == 1 }) // true
println(l) // [6, 7] - all ones removed
}
...
true
[2, 3, 3, 4, 5, 6, 7, 1, 1, 1]
2
[3, 3, 4, 5, 6, 7, 1, 1, 1]
java.lang.IndexOutOfBoundsException: Index: 10000, Size: 9
true
[6, 7, 1, 1, 1]
true
[6, 7]

Finally i find the answer in Kotlin doc by myself. Kotlin will box generics
int to Integer if you declare the variable as Int?, because only an Object can be null.You can use the tool in android studio which can show the kotlin bytecode to find out that.
If we call java method like the question image:
val a:Int = 0
remove(a) // will call java method remove(int position)
val a:Int? = 0
remove(a) // will call java method remove(T t) to remove object
the result is different! If have better choice, we should avoid use like that.

Seems that other answers just give alternatives of remove(int position) but they didn't answer the question directly (according to the edit).
So you can use this code:
val list = mutableListOf("ah!", "I", "died!")
(list as java.util.List<String>).remove(1)
println(list)
Result:
[ah!, died!]
That's it! You've successfully invoked remove(int position) from Java.
This will raise some warnings, just ignore them.
Try it online!

Related

problem with Overriding toString on object

I am writing a myset class that has a Array of Object. I am trying override the toString method but it is not printing the elements when I call testing.
here is the method override
#Override
public String toString()
{
if(size==0){
return "[]";
}else{
string result="["+ arr[0];
for(int i=1;i<size;i++)
{
result+=", "+arr[i];
}
}
result+="]";
return result;
}
this is the array I am Trying to call
private static Object[] arr={1, 2, 3, 4 ,5, 6, 'A', 8 , "easha", 0, 44};
System.out.print(arr);
this is how I am calling it in the main
this is the result I get
[Ljava.lang.Object;#1dbd16a6%
FYI: I have a size method that calculates the size.
I was expecting the array to look like this {1, 2, 3, 4 ,5, 6, 'A', 8 , "easha", 0, 44}
but the result is this [Ljava.lang.Object;#1dbd16a6% `

How to convert Comparator to compare?

Here's the code that I'm trying to get.
public static final Comparator<Youku> AscDurRevCreationDate =
Comparator.comparing(Youku::getDuration)
.reversed()
.thenComparing(Youku::getDateCreation)
.reversed();
And the code below is the one I'm trying to convert it to. However, I'm getting a little different result from this code below. Btw, I'm using the Duration object in here.
#Override
public int compare(Youku obj1, Youku obj2) {
Integer duration = obj1.getDuration().compareTo(obj2.getDuration());
Integer dateCreation = obj2.getDateCreation().compareTo(obj1.getDateCreation());
return duration.compareTo(dateCreation );
}
Explanation
Looking at your Comparator:
public static final Comparator<Youku> AscDurRevCreationDate =
Comparator.comparing(Youku::getDuration)
.reversed()
.thenComparing(Youku::getDateCreation)
.reversed();
You want to compare Youkus by their duration (getDuration), descending and not ascending (reversed()) and if two durations are equal, break the ties by the creation date (getDateCreation), descending.
The correct Comparable implementation for that looks like:
#Override
public int compareTo(Youku other) {
int durationResult = Integer.compare(getDuration(), other.getDuration());
durationResult *= -1; // for reversed
if (durationResult != 0) { // different durations
return durationResult;
}
// break ties using creation date
int creationDateResult = Integer.compare(getDateCreation(), other.getDateCreation());
creationDateResult *= -1;
return creationDateResult;
}
or in compact:
int durationResult = -1 * Integer.compare(getDuration(), other.getDuration());
return durationResult != 0
? durationResult
: -1 * Integer.compare(getDateCreation(), other.getDateCreation());
Based on Comparator
Alternatively you can also implement the method based on the Comparator you already have:
public static final Comparator<Youku> comparator =
Comparator.comparing(Youku::getDuration)
.reversed()
.thenComparing(Youku::getDateCreation)
.reversed();
...
#Override
public int compareTo(Youku other) {
return comparator.compare(this, other);
}
Notes
Your code attempt does not show a Comparable implementation but a manual implementation for a Comparator. I suppose you confused something there.
Looking at your original requirement I feel compelled to point out that specifying reversed() reverses the desired order of all the previously specified sorting orders. So assuming a default ascending sorting order for all, the following:
public static final Comparator<Youku> comparator =
Comparator.comparing(Youku::getDuration)
.reversed()
.thenComparing(Youku::getDateCreation)
.reversed();
Sorts first in ascending order of duration and then in descending order of creation since the second reversed() reverses the previous orders. So to sort both in descending, remove the first reversed().
Say you wanted to sort by duration in ascending order but by creation in descending order. Then you could do it this way.
public static final Comparator<Youku> comparator =
Comparator.comparing(Youku::getDuration)
.thenComparing(Youku::getDateCreation, Comparator.reversedOrder());
The Comparator.reverseOrder() only affects the current mode of sorting.
If you want to see an easy example of this, check out the following. You can adjust the comparator to see the different results.
int[][] vals = { { 30, 6 }, { 40, 7 }, { 40, 8 }, { 10, 1 },
{ 10, 2 }, { 20, 3 }, { 20, 4 }, { 30, 5 }, { 50, 9 },
{ 50, 10 }, { 60, 11 }, { 60, 12 } };
// ascending first, descending second
Comparator<int[]> comp =
Comparator.comparing((int[] a) -> a[0])
.reversed()
.thenComparing(a -> a[1])
.reversed();
Arrays.sort(vals,comp);
for(int[] v : vals) {
System.out.println(Arrays.toString(v));
}
Prints
[10, 2]
[10, 1]
[20, 4]
[20, 3]
[30, 6]
[30, 5]
[40, 8]
[40, 7]
[50, 10]
[50, 9]
[60, 12]
[60, 11]

How to convert intArray to ArrayList<Int> in Kotlin?

From
val array = intArrayOf(5, 3, 0, 2, 4, 1, 0, 5, 2, 3, 1, 4)
I need to convert to ArrayList<Int>
I have tried array.toTypedArray()
But it converted to Array<Int> instead
You can use toCollection function and specify ArrayList as a mutable collection to fill:
val arrayList = intArrayOf(1, 2, 5).toCollection(ArrayList())
You can get List<Int> with a simple toList call like so:
val list = intArrayOf(5, 3, 0, 2).toList()
However if you really need ArrayList you can create it too:
val list = arrayListOf(*intArrayOf(5, 3, 0, 2).toTypedArray())
or using more idiomatic Kotlin API as suggested by #Ilya:
val arrayList = intArrayOf(1, 2, 5).toCollection(ArrayList())
Or if you'd like to do the above yourself and save some allocations:
val arrayList = intArrayOf(5, 3, 0, 2).let { intList ->
ArrayList<Int>(intList.size).apply { intList.forEach { add(it) } }
}

Combine values with Java8 stream

If I have a list with integers, is there a way to construct another list, where integers are summed if the difference to the head of the new list is below a threashold? I would like to solve this using Java 8 streams. It should work similar to the Scan operator of RxJava.
Example: 5, 2, 2, 5, 13
Threashold: 2
Result: 5, 9, 13
Intermediate results:
5
5, 2
5, 4 (2 and 2 summed)
5, 9 (4 and 5 summed)
5, 9, 13
Sequential Stream solution may look like this:
List<Integer> result = Stream.of(5, 2, 2, 5, 13).collect(ArrayList::new, (list, n) -> {
if(!list.isEmpty() && Math.abs(list.get(list.size()-1)-n) < 2)
list.set(list.size()-1, list.get(list.size()-1)+n);
else
list.add(n);
}, (l1, l2) -> {throw new UnsupportedOperationException();});
System.out.println(result);
Though it looks not much better as good old solution:
List<Integer> input = Arrays.asList(5, 2, 2, 5, 13);
List<Integer> list = new ArrayList<>();
for(Integer n : input) {
if(!list.isEmpty() && Math.abs(list.get(list.size()-1)-n) < 2)
list.set(list.size()-1, list.get(list.size()-1)+n);
else
list.add(n);
}
System.out.println(list);
Seems that your problem is not associative, so it cannot be easily parallelized. For example, if you split the input into two groups like this (5, 2), (2, 5, 13), you cannot say whether the first two items of the second group should be merged until the first group is processed. Thus I cannot specify the proper combiner function.
As Tagir Valeev observed, (+1) the combining function is not associative, so reduce() won't work, and it's not possible to write a combiner function for a Collector. Instead, this combining function needs to be applied left-to-right, with the previous partial result being fed into the next operation. This is called a fold-left operation, and unfortunately Java streams don't have such an operation.
(Should they? Let me know.)
It's possible to sort-of write your own fold-left operation using forEachOrdered while capturing and mutating an object to hold partial state. First, let's extract the combining function into its own method:
// extracted from Tagir Valeev's answer
void combine(List<Integer> list, int n) {
if (!list.isEmpty() && Math.abs(list.get(list.size()-1)-n) < 2)
list.set(list.size()-1, list.get(list.size()-1)+n);
else
list.add(n);
}
Then, create the initial result list and call the combining function from within forEachOrdered:
List<Integer> result = new ArrayList<>();
IntStream.of(5, 2, 2, 5, 13)
.forEachOrdered(n -> combine(result, n));
This gives the desired result of
[5, 9, 13]
In principle this can be done on a parallel stream, but performance will probably degrade to sequential given the semantics of forEachOrdered. Also note that the forEachOrdered operations are performed one at a time, so we needn't worry about thread safety of the data we're mutating.
I know that the Stream's masters "Tagir Valeev" and "Stuart Marks" already pointed out that reduce() will not work because the combining function is not associative, and I'm risking a couple of downvotes here. Anyway:
What about if we force the stream to be sequential? Wouldn't we be able then to use reduce? Isn't the associativity property only needed when using parallelism?
Stream<Integer> s = Stream.of(5, 2, 2, 5, 13);
LinkedList<Integer> result = s.sequential().reduce(new LinkedList<Integer>(),
(list, el) -> {
if (list.isEmpty() || Math.abs(list.getLast() - el) >= 2) {
list.add(el);
} else {
list.set(list.size() - 1, list.getLast() + el);
}
return list;
}, (list1, list2) -> {
//don't really needed, as we are sequential
list1.addAll(list2); return list1;
});
Java 8 way is define custom IntSpliterator class:
static class IntThreasholdSpliterator extends Spliterators.AbstractIntSpliterator {
private PrimitiveIterator.OfInt it;
private int threashold;
private int sum;
public IntThreasholdSpliterator(int threashold, IntStream stream, long est) {
super(est, ORDERED );
this.it = stream.iterator();
this.threashold = threashold;
}
#Override
public boolean tryAdvance(IntConsumer action) {
if(!it.hasNext()){
return false;
}
int next = it.nextInt();
if(next<threashold){
sum += next;
}else {
action.accept(next + sum);
sum = 0;
}
return true;
}
}
public static void main( String[] args )
{
IntThreasholdSpliterator s = new IntThreasholdSpliterator(3, IntStream.of(5, 2, 2, 5, 13), 5);
List<Integer> rs= StreamSupport.intStream(s, false).mapToObj(Integer::valueOf).collect(toList());
System.out.println(rs);
}
Also you can hack it as
List<Integer> list = Arrays.asList(5, 2, 2, 5, 13);
int[] sum = {0};
list = list.stream().filter(s -> {
if(s<=2) sum[0]+=s;
return s>2;
}).map(s -> {
int rs = s + sum[0];
sum[0] = 0;
return rs;
}).collect(toList());
System.out.println(list);
But I am not sure that this hack is good idea for production code.

Problems with Java generics and collections

I have a class that represents a tree-like structure, the essential bits look like this:
public Node<T> placeAll(Collection<T> elements){
for (T e : elements)
addElement(e);
// LOG/DEBUG etc
return root;
}
public void addElement(T el) {
Node<T> node = new Node<T>(el);
addElement(root, node);
}
private void addElement(Node<T> parent, Node<T> child) {
// .... PLACE THE NODE
}
Now this works perfectly fine when I place the nodes one by one in a test case:
public void test() {
List<Integer> s1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
// 13 more lists
List<Integer> s15 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 221, 251);
Hypergraph<Object> hg = new Hypergraph<>(...);
hg.addElement(s1);
System.out.println(hg.getRoot().toStringTree());
System.out.println();
.
.
.
hg.addElement(s15);
System.out.println(hg.getRoot().toStringTree());
System.out.println();
}
If I add the following line
hg.placeAll(Arrays.asList(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15));
to my test case, I get an error regarding the use of generics:
The method placeAll(Collection<Object>) in the type Hypergraph<Object> is not applicable for the arguments (List<List<Integer>>)
I don't quite understand this... If addElement(T el) works fine when I call it with T resolved to List<Integer>, why does List<List<Integer>> comply to placeAll(Collection<T> c)? Considering that List<T> is a Collection<T> I can't make sense out of this..
The problem is that the method expects a Collection<Object> (as T seems to be Object in your example), but you are passing a Collection<List<Integer>>. And while a List<Integer> is an Object, a Collection<List<Integer>> is not a subclass of a Collection<Object>.
Change the method signature to accept a Collection<? extends T>, then it should work.
public Node<T> placeAll(Collection<? extends T> elements) {

Categories