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) {
Related
This question already has answers here:
Flatten nested arrays in java
(9 answers)
Closed 3 months ago.
This question was asked to me in Razorpay. I could not come up with a solution. Can anyone help me in writing Java code for this.
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10};
Answer should be:
Integer[] = {1,2,3,4,5,6,7,8,9,10};
i.e. all the Integer elements should be stored
What I did is
for(Object obj: array){
if(obj instanceof Integer) list.add((int)(obj));
}
Which results in -> 1,2,8,9,10. How do I add 3,4,5,6,7 inside list?
As there's no finite depth of nesting of Object[] you'll need a recursive approach:
import java.util.ArrayList;
import java.util.List;
public class Answer {
static void extractIntegers(Object[] source, List<Integer> destination) {
for (Object i : source) {
if (i instanceof Object[] array) {
extractIntegers(array, destination);
} else if (i instanceof Integer integer) {
destination.add(integer);
} else {
throw new IllegalArgumentException("Unexpected: " + i);
}
}
}
public static void main(String[] args) {
List<Integer> ints = new ArrayList<>();
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10};
extractIntegers(array, ints);
System.out.println(ints);
}
}
Note that I'm using the recently added "pattern matching for instanceof" feature of Java.
You could ignore objects which are not Object[] or Integer. I've chosen to throw an excpetion.
The operation you are looking for is called flattening an array. Your input is an array of Object which can consist of either Integer or Object[]. So we have to handle both cases here, and it is easier done with recursion:
Write a function flatten(Object[] arr) that takes in an Object[] as parameter. The function will return List<Integer> which is the result after arr is flattened.
The logic is simple for the recursive flatten() function:
create empty result_array
for each obj in Object[]:
if obj is an Integer:
add obj to the result_array
else obj is Object[]:
flat_obj := flatten(obj)
add all integers of flat_obj into result_array
return result_array
Here are the Java code for the above logic implemented. Hope it helps!
public class Test {
public static List<Integer> flatten(Object[] array) {
List<Integer> result = new ArrayList<>();
for (Object o: array) {
if (o instanceof Object[])
result.addAll( flatten( (Object[]) o) );
else
result.add((Integer) o);
}
return result;
}
public static void main(String[] args) {
Object[] array = { 1, 2, new Object[]{ 3, 4, new Object[]{ 5 }, 6, 7 }, 8, 9, 10};
System.out.println( flatten(array) );
}
}
You're only checking for integers, but you also have arrays in your array.
Together with the instanceof Integer check, you should also add a check on instanceof Object[]. Be careful that also the Object[] contains an Object[]. So you'll have to have the same check inside of it as well. You shall have 3 loops in the end, each of which will have checks on instanceof Integer and instanceof Object[]
I'm learning Java lambdas for school, and I am stuck for a couple of days now.
Background
I have a list of pumps which I have to sort out on power, last revision, …
I already wrote a Comparator that's returning a List<Pump>:
class PowerComparator implements Comparator<Pomp> {
#Override
public int compare(Pump pump1 , Pump pump2) {
return Double.compare(pump1.getPower(), pump2.getPower());
}
}
I have to write one function that's returning a List<Pump> that can returning a sorted list (power, revision, ...) using a lambda.
The method signature is:
public List<Pump> sortedBy(Function<Pump, Comparable<Pump>> function)
I know that the Function interface is returning a Comparator, but I don't know how to use the function in it.
Below is what I already found (it's not correct). I am really stuck here.
public List<Pump> sortedBy(Function<Pump, Comparable<Pump>> function){
List<Pump> sortBy = new ArrayList<Pump>(pumps);
function.apply((Pump) ->Comparator.comparing(pumps::comparator));
Collections.sort(sortBy, Comparator.comparing(function.apply(pumps);
return sortBy;
}
Additional info (in dutch)
public class Data {
private static List<Pomp> data;
public static List<Pomp> getData() {
data = new ArrayList<>();
data.add(new Pomp("J6706A", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 1, 10), true, 500.0, "Slurry pomp"));
data.add(new Pomp("J6707A", 55.5, 1, Aandrijving.MOTOR, LocalDate.of(2022, 2, 10), false, 500.0, "Clarified pomp"));
data.add(new Pomp("J6706B", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 3, 10), true, 500.0, "Slurry pomp"));
data.add(new Pomp("J6706C", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 4, 10), true, 500.0, "Slurry pomp"));
data.add(new Pomp("J6705A", 62, 1, Aandrijving.MOTOR, LocalDate.of(2022, 5, 10), false, 250, "Voedings pomp"));
data.add(new Pomp("J6705B", 35, 2, Aandrijving.TURBINE, LocalDate.of(2022, 6, 10), false, 150, "Voedings pomp"));
data.add(new Pomp("J6708B", 100.0, 2, Aandrijving.TURBINE, LocalDate.of(2022, 7, 10), false, 300, "HCO circ pomp"));
return data;
}
}
public class Pompen {
private TreeSet<Pomp> pompen = new TreeSet<>();
public void add(Pomp pomp) {
pompen.add(pomp);
}
class VermogenComparator implements Comparator<Pomp> {
#Override
public int compare(Pomp pomp1 , Pomp pomp2) {
return Double.compare(pomp1.getVermogen(), pomp2.getVermogen());
}
}
class RevisieComparator implements Comparator<Pomp> {
#Override
public int compare(Pomp pomp1 , Pomp pomp2) {
return pomp1.getLaatsteRevisie().compareTo(pomp2.getLaatsteRevisie());
}
}
class Zelfontbranding implements Comparator<Pomp> {
#Override
public int compare(Pomp pomp1 , Pomp pomp2) {
return Boolean.compare(pomp1.getBovenZelfOntbranding(), pomp2.getBovenZelfOntbranding());
}
}
Because of your example using sortBy(Pump::getName), I believe that the intent here is to use the Comparator.comparing() factory to create a comparator that extracts a sort key from each object. However, this requires some changes to the generic types used in the prescribed method signature. Working code would look something like this:
public <U extends Comparable<? super U>> List<Pomp> sortedBy(Function<Pomp, ? extends U> toKey) {
List<Pomp> sorted = new ArrayList<>(pompen);
sorted.sort(Comparator.comparing(toKey));
return sorted;
}
This will accept lambdas like Pomp::getNaam as long as the indicated property is Comparable:
System.out.println("Pumps sorted on power:");
pompen.sortedBy(Pomp::getVermogen).forEach(System.out::println);
A better design would be to pass a Comparator; while it's a tiny bit more work for the caller, it gives them full control over the sorting. For example, they can specify a secondary sort key, or reverse the order. Or one could go another step further and simply return a copy of the pumps collection as a list and let the caller do whatever they wish with it.
If permitted, you could change the API to this:
public List<Pomp> sortedBy(Comparator<? super Pomp> order) {
List<Pomp> sorted = new ArrayList<>(pompen);
sorted.sort(order);
return sorted;
}
The caller would then be responsible for creating a Comparator that meets their need:
/* Like this: */
List<Pomp> sortedByName = pompen.sortedBy(Comparator.comparing(Pomp::getNaam));
/* Or this: */
List<Pomp> pumpsDescendingPower =
pompen.sortedBy(Comparator.comparing(Pomp::getVermogen).reversed());
This approach is more idiomatic for Java.
I have two list as shown below
List<Test> fisrtList= Arrays.asList(
new Test(1, 1L),
new Test(2, 3L),
new Test(2, 4L)
);
List<Long> secondList=Arrays.asList(3L, 5L);
//Find value of second list that are not in first list
Expected answer from the comparision should be 5L as it is not in firstList.
Here is my Test class
public class Test {
public Test(int id, Long idNo) {
this.id=id;
this.idNo=idNo;
}
private int id;
private Long idNo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Long getIdNo() {
return idNo;
}
public void setIdNo(Long idNo) {
this.idNo = idNo;
}
}
How can I find the Long values from secondList that are not in the firstList?
If you want to use streams for this purpose the most efficient approach will look like this:
public static List<Long> removeIntersection(List<Long> source, List<Test> valuesToRemove) {
Set<Long> toRemove = toSet(valuesToRemove);
return source.stream()
.filter(num -> !toRemove.contains(num))
.collect(Collectors.toList());
}
private static Set<Long> toSet(List<Test> valuesToRemove) {
return valuesToRemove.stream()
.map(Test::getIdNo)
.collect(Collectors.toSet());
}
The same result could be achieved by utilizing removeAll() and retainAll() methods from the Collection interface. These methods are optimized for ArrayList and perform in a linear time.
You just have to coerce your list of test objects to a list of Long and make a copy of the second list which gonna be mutated.
To demonstrate how these methods work let's consider the following example with lists of Integer values.
removeAll() will remove all elements contained in the given collection from this collection
retainAll() will retain only elements contained in both collections
public static void main(String[] args) {
List<Integer> source = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
List<Integer> valuesToRemove = new ArrayList<>(List.of(1, 2, 3, 4));
source.removeAll(valuesToRemove);
System.out.println("result of removeAll: " + source);
source = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9));
List<Integer> valuesToRetain = new ArrayList<>(List.of(5, 6, 7, 8, 9));
source.retainAll(valuesToRetain);
System.out.println("result of retainAll: " + source);
}
output
result of removeAll: [5, 6, 7, 8, 9]
result of retainAll: [5, 6, 7, 8, 9]
This will do it
secondList.removeAll(firstList);
If you need secondList to not be modified you must make a deep copy first and use the deep copy instead of secondList.
Here is my collection. Here I try to make my own implemetation with special Comparator that sorts Integer elements by its absolute values.
class SortedByAbsoluteValueIntegerSet extends TreeSet {
private TreeSet<Integer> mySet;
public SortedByAbsoluteValueIntegerSet() {
mySet = new TreeSet<Integer>(Comparator.comparing(Math::abs));
}
#Override
public boolean add(Object o) {
mySet.add((Integer) o);
return true;
}
#Override
public boolean addAll(Collection c) {
for (Object o : c) {
mySet.add((Integer) o);
}
return true;
}
public Iterator<Integer> iterator() {
return mySet.iterator();
}
(and other methods)
Main class. Everything seems to work correct except toString() method. When I overwrite this method without lambdas it works. But! This method is in tests and I mustn't change it. I just copied it to Main class trying to understand the problem. And problem I want to solve is somewhere in SortedByAbsoluteValueIntegerSet class.
public static void main(String[] args) {
Set<Integer> set = new SortedByAbsoluteValueIntegerSet();
Arrays.asList(1, 3, 5, 7, 9).forEach(set::add);
set.addAll(Arrays.asList(-2, -4, -6, -8, -10));
System.out.println("set.size() = " + set.size()); //OUTPUT:"set.size() = 10"
System.out.println("set = " + set); //OUTPUT:"set = [-10, -8, -6, -4, -2, 1, 3, 5, 7, 9]"
System.out.println("toString(set) = " + toString(set)); //OUTPUT:"toString(set) = "
}
private static String toString(final Collection<Integer> collection) {
return String.join(" ", collection.stream()
.map(i -> Integer.toString(i))
.toArray(String[]::new));
}
This is another realization that works good. So what's the difference?
private static String toString(final Collection<Integer> collection) {
List<String> list = new ArrayList<>();
for (Integer i : collection) {
String s = Integer.toString(i);
list.add(s);
}
return String.join(" ", list.toArray(new String[0]));
}
You shouldn't be extending TreeSet and having a TreeSet field. One or the other, but both makes no sense.
This is probably actually the cause of your issue: you have two different TreeSets associated with each SortedByAbsoluteValueIntegerSet, and the one you're adding to and the one toString() is getting are different.
Extend AbstractSet instead.
You seem to not completely have understood the toString() method yet. This method should be in your SortedByAbsoluteValueIntegerSet class and has to be public and not private.
Maybe this link can help you to understand the toString() method a bit better:
https://www.javatpoint.com/understanding-toString()-method
Is it possible to create a linked list in Java, with the ability to add new links anywhere in the middle (not just at the beginning or end) of the list -- if possible, without copy-pasting in memory large parts of the list to accommodate for entry of a new link?
If so, please post your example!!
You can use LinkedList to do this.
List<Integer> ints = new LinkedList<Integer>();
for (int i = 0; i <= 10; i++)
ints.add(i / 2, i);
System.out.println(ints);
prints
[1, 3, 5, 7, 9, 10, 8, 6, 4, 2, 0]
As you can see it has been adding entries in the middle of the list.
The LinkedList class in Java already does this, by means of its add(index, element) method.
In pseudo code something link this is a good place to start:
public LinkedList<E> implements List<E>{
...
public void add(int index, E element){
Node<E> current=findNodeAt(index);
//add in your logic to insert this node at this location
//probably something like (depending on your linking)
element.setNext({current nodes next value})
current.setnext(element);
}
private Node<E> findNodeAt(index){
//iterate through list until you reach the index or end of the list
//then return that node
}
...
}
public Node<E>{
private Node<E> next;
...
Node<E> setNext(Node<E> next){
Node<E> previousNext=next;
this.next=next;
return previousNext;
}
...
}
LinkedList Implements 'List' Interface, and it has the add method you need : http://docs.oracle.com/javase/7/docs/api/java/util/List.html#add%28int,%20E%29