So, I'm new to Java Generics. I'm building a graph and an adjacency list using hashMap and hashSet. I've written the class and its methods using Generics. I've also extended T to Node.
For printing the adjacency list,
public class Graph<T extends Node>{
public static int time;
private HashMap<T, HashSet<T>> adjacencyList;
public Graph(){
this.adjacencyList = new HashMap<>();
}
void printAdjacencyList(HashMap<T,HashSet<T>> adj){
for(T n : adj.keySet()){
System.out.print("Key: " + n.getValue()+"\t");
Iterator<T> i = adj.get(n).iterator();
while(i.hasNext()){
System.out.print(" "+i.next().getValue());
}
System.out.println();
}
}
}
public static void main(String[] args){
Graph<Node> G = new Graph<>();
// have added vertices and edges
printAdjacencyList(G.adjacencyList);
}
Here,G.adjacencyList is of the type HashMap<Node,HashSet< Node >> .
Node is another class with a few members.
But , I'm encountering compilation error:
The method printAdjacencyList(HashMap<T,HashSet < T >>) in the type Graph is not applicable for the arguments (HashMap<Node,HashSet < Node >>)
So, as far as I can understand it's saying me to explicitly write a function with HashMap<Node, HashSet < Node > > as arguments.
Is there any way that I can use the generic function somehow (instead of writing a new function with required arguments).
The problem is that you want to pass a HashMap<Node, Set> but it want a HastMap<Node, HastSet>.
Every HashSet also fulfill the requirement of Set but not vice versa.
Solution 1:
void printAdjacencyList(HashMap<T,HashSet<T>> adj){ =>
void printAdjacencyList(HashMap<T,Set<T>> adj){
Solution 2:
private HashMap<T, Set<T>> adjacencyList; => private HashMap<T, HashSet<T>> adjacencyList;
Related
I am looking for a clean and simple way to iterate over two ArrayLists that are related directly in that each index of one maps to the index of another (in relationship).
Currently, I'm doing it via a simple for loop and I tried looking into lambdas and for-each loops but don't see a way to apply it to two lists at the same time that are of the same size.
firstList: ["Blue", "Red", "Green"]
secondList: ["Sky", "Roses", "Grass"]
for(int i = 0; i < firstList.size(); i++){
System.out.println(firstList.get(i) + " " + secondList.get(i));
}
Result:
Blue Sky
Red Roses
Green Grass
Is there a way to effectively iterate over both lists simultaneously using a lambda or a for-each loop to avoid using a for loop?
What you have it is already pretty efficient (assuming that you are using ArrayList), concise and readable. However, this type of scenarios:
I am looking for a clean and simple way to iterate over two ArrayLists
that are related directly in that each index of one maps to the index
of another (in relationship).
typically require a class that defines the relationship, in your case:
public class MyC {
private final String color;
private final String object;
public MyC(String color, String object) {
this.color = color;
this.object = object;
}
public String getColor(){
return color;
}
public String getObject(){
return object;
}
#Override
public String toString() {
return "MyC{" +
"color='" + color + '\'' +
", object='" + object + '\'' +
'}';
}
}
then the two lists would become one:
List<MyC> list = List.of(new MyC("Blue", "Sky"), new MyC("Red", "Roses"), new MyC("Green", "Grass") );
and then you can use:
list.forEach(System.out::println);
The Answer by dreamcrash is correct: While your looping of a pair of arrays works, you should instead take advantage of Java as a OOP language by defining your own class.
Record
Defining such a class is even simpler in Java 16 with the new records feature. Write your class as a record when it’s main purpose is communicating data, transparently and immutably.
A record is very brief by default. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString. You need only declare the type and name of each member field.
record ColorNoun ( String color , String noun ) {}
Use a record like a conventional class. Instantiate with new.
ColorNoun blueSky = new ColorNoun ( "Blue" , "Sky" ) ;
Note that a record can be declared locally within a method, or declared separately like a conventional class.
You can use the "range"-statement to iterate the index with a lambda expression.
https://www.baeldung.com/java-stream-indices
Like this:
List<String> firstList = Arrays.asList("Blue","Red","Green");
List<String> secondList = Arrays.asList("Sky","Roses","Grass");
IntStream
.range(0, firstList.size())
.forEach(index ->
System.out.println(String.format("%s %s", firstList.get(index), secondList.get(index)))
);
It's basically the same approach - just with lambdas.
The only way to get rid of the index-based access is by using a different data-structure or use an alternating iteration technique as shown in the other answers.
If your intention is to just avoid using a for loop, then you could try the below:
Iterator<String> iterator = secondList.iterator();
firstList.forEach(s -> System.out.println(s + " " + iterator.next()));
Or even add to a StringBuilder and then display the result in the end.
All the other answers are correct and the preferred solution should always be the one shown by #Basil Bourque , but as others pointed out in the comments, iterating a non-array-based list using indexes is not very efficient. However, iterating using an iterator should (where each implementation can provide an efficient implementation) is.
Here is an example how you can iterate 2 lists using their iterator:
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiConsumer;
public class IterateTwoListsExample {
public static void main(String[] args) {
List<String> firstList = Arrays.asList("Blue","Red","Green");
List<String> secondList = Arrays.asList("Sky","Roses","Grass");
forEach(firstList, secondList, (first, second) -> System.out.printf("%s %s%n", first, second));
}
public static <T0, T1> void forEach(List<? extends T0> first, List<? extends T1> second, BiConsumer<? super T0, ? super T1> consumer) {
final Iterator<? extends T0> firstIt = first.iterator();
final Iterator<? extends T1> secondIt = second.iterator();
while (firstIt.hasNext() && secondIt.hasNext()) {
consumer.accept(firstIt.next(), secondIt.next());
}
}
}
I'm kind of new to generics in Java and I've faced such a problem: Let's say you have your own List implementation and you want to provide a mechanism to simultaneously convert all elements using some kind of mapping (functional interface) and collect them into a new list.
While the idea and use of functional interface (IMapper in my case) is straightforwad I can't quite think of what signature a function performing mapping should have?
Here's a little use case example and what I thought of as well. It does not work unfortunately and I guess the main problem is: How the second V param type should be passed in such case?
public interface IMapper<T,V> { V map(T v); }
public class MyList<T> extends ArrayList<T> {
public MyList<V> map(IMapper <T,V> mapper) {
MyList<V> list = new MyList<>();
for(T v : this) {
list.add(mapper.map(v));
}
return list;
}
}
// in main
MyList<Integer> list1 = new MyList<>();
// fill etc..
IMapper<Integer,String> m = (i) -> { return i.toString(); };
// "Change" list
MyList<String> list2 = list1.map(m);
PS:
I think that such thing is most probably already implemented in Java (stream() and what follows I guess?) however it suppose to be exercise for me. Any tip would be much appreciated :)
You can add the map result type to you function definition as following:
class MyList<T> extends ArrayList<T> {
public <V> MyList<V> map(IMapper<T, V> mapper) {
MyList<V> list = new MyList<>();
for (T v : this) {
list.add(mapper.map(v));
}
return list;
}
}
Example:
MyList<Integer> number = new MyList<>();
number.add(1);
number.add(2);
number.add(3);
number.map(v -> "#" + v).forEach(System.out::println);
And you can have the same result using Java8 streams as following:
List<Integer> numberStream = new ArrayList<>();
numberStream.add(1);
numberStream.add(2);
numberStream.add(3);
numberStream.stream().map(v -> "#" + v).forEach(System.out::println);
You can define the generic parameter as a type parameter on your map method. Like this:
public <V> MyList<V> map(IMapper <T,V> mapper) {
...
}
Type parameters can be defined in two ways, either on a class or on a method. If it's defined on a class, it can be used throughout the class. If it's defined on a method, it can only be used in that method.
In your case, the T parameter is defined on the class, while the V parameter can be defined on the method.
I have a class called SparseMatrix. It contains an ArrayList of Nodes (also class). I am wondering of how to iterate through the Array and access a value in Node. I have tried the following:
//Assume that the member variables in SparseMatrix and Node are fully defined.
class SparseMatrix {
ArrayList filled_data_ = new ArrayList();
//Constructor, setter (both work)
// The problem is that I seem to not be allowed to use the operator[] on
// this type of array.
int get (int row, int column) {
for (int i = 0; i < filled_data_.size(); i++){
if (row * max_row + column == filled_data[i].getLocation()) {
return filled_data[i].getSize();
}
}
return defualt_value_;
}
}
I will probably switch to static arrays (and remake it every time I add an object). If anyone has a solution, I would very much appreciate you sharing it with me. Also, thank you in advance for helping me.
Feel free to ask questions if you don't understand anything here.
Assuming filled_data_ is a list that contains list of objects of a class named Node.
List<Nodes> filled_data_ = new ArrayList<>();
for (Node data : filled_data_) {
data.getVariable1();
data.getVariable2();
}
More info http://crunchify.com/how-to-iterate-through-java-list-4-way-to-iterate-through-loop/
First of all, you should not use raw types. See this link for more info: What is a raw type and why shouldn't we use it?
The fix is to declare the type of object held by your array list. Change the declaration to:
ArrayList<Node> filled_data_ = new ArrayList<>();
Then you can access each element in the array list using filled_data_.get(i) (as opposed to filled_data_[i], which would work for a regular array).
`filled_data_.get(i)`
The above will return the element at index i. Documentation here: https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#get(int)
If you didn't use generic, then you need to cast the object
//Assume that the member variables in SparseMatrix and Node are fully defined.
class SparseMatrix {
ArrayList filled_data_ = new ArrayList();
//Constructor, setter (both work)
// The problem is that I seem to not be allowed to use the operator[] on
// this type of array.
int get (int row, int column) {
for (int i = 0; i < filled_data_.size(); i++){
Node node = (Node)filled_data.get(i);
if (row * max_row + column == node.getLocation()) {
return node.getSize();
}
}
return defualt_value_;
}
}
If array list contains Nodes which defines getLocation() you could use :
((Nodes)filled_data_.get(i)).getLocation()
You could also define
ArrayList<Nodes> filled_data_ = new ArrayList<Nodes>();
When you create the ArrayList object, you should specify the type of the contained elements with <> brackets. It is also good to keep the reference to the List interface - not ArrayList class. To iterate through such a collection, use foreach loop:
Here is an example of the Node class:
public class Node {
private int value;
public Node(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
Here is an example of the Main class:
public class Main {
public static void main(String[] args) {
List<Node> filledData = new ArrayList<Node>();
filledData.add(new Node(1));
filledData.add(new Node(2));
filledData.add(new Node(3));
for (Node n : filledData) {
System.out.println(n.getValue());
}
}
}
For example... Adjacency list realiszation
public class Vertex {
String name;
boolean visited;
public Vertex(String name) {
this.name=name;
visited=false;
}
public int hashCode() {
return name.hashCode();
}
public boolean equals(Object ob) {
return hashCode()==ob.hashCode();
}
public String toString() {
return name;
}
}
The main class
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) {
PrintWriter pw=new PrintWriter(System.out);
Map<Vertex,Vertex> m=new HashMap();
m.put(new Vertex("a"), new Vertex("b"));// a ---> b
m.put(new Vertex("a"), new Vertex("c"));// a ---> c
m.put(new Vertex("a"), new Vertex("d"));// a ---> d
pw.println("All vertex from: ");
for (Vertex vert_from:m.keySet()) {
pw.print(vert_from+" ");
}
pw.println();
pw.println("All vertices to: ");
for (Vertex vert_to:m.values()) {
pw.print(vert_to+" ");
}
pw.close();
}
}
It outputs:
All vertex from:
a
All vertices to:
d
But i need that "All vertices to: b c d"
How can I fix that?
A Map indeed stores a single value per key. You could, however, store a collection in value, say a Set:
Map<Vertex, Set<Vertex>> m = new HashMap<>();
Set<Vertex> set = new HashSet<>();
set.add(new Vertex("b"));
set.add(new Vertex("c"));
set.add(new Vertex("d"));
m.add (new Vertex("a"), set);
Alternatively, you can use one of the common implementations of this concept, such as Apache Commons Collections' MultiValueMap or Guava's HashMultiMap.
What you are asking for is called a "Multi Map".
If you are using Java 8 then this is quite neat, first you need a Map<Vertex, Collection<Vertex>>. I don't know what properties you need from the Collection, that you will have to investigate yourself.
As you have overridden equals and hashCode (incorrectly, but a valiant attempt), I will assume that you want to have the items unique by name. I will also assume that order matters, so LinkedHashSet seems a good choice.
final Map<Vertex, Collection<Vertex>> graph = new HashMap<>();
Now, to add an item to the Map we need to first ensure that the Collection for that key is not null. This is exactly what the new Map.computeIfAbsent comes in.
final Vertex a = new Vertex("a");
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("b"));
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("c"));
graph.computeIfAbsent(a, v -> new LinkedHashSet<>()).add(new Vertex("d"));
So what this does is, when inserting a into the Map, if the Collection for that key is null, computes a new value for it.
Now to get all values for a key:
Collection<Vertex> values = graph.get(a);
You could wrap the Map<Vertex, Collection<Vertex>> in some sort of Graph class to hide the implementation details and to have neater code:
class Graph {
final Map<Vertex, Collection<Vertex>> graph = new HashMap<>();
public void put(final Vertex key, final Vertex value) {
graph.computeIfAbsent(key, k -> new LinkedHashSet<>()).add(value);
}
public Collection<Vertex> get(final Vertex key) {
return Optional.ofNullable(graph.get(key)).orElse(Collections.EMPTY_SET);
}
}
This also deals with returning an empty collection instead of null if a key is not present in the Map. Depending on your use case you might also want to wrap the returned Collection with Collections.unmodifiableCollection to prevent unwanted modifications:
public Collection<Vertex> get(final Vertex key) {
return Optional.ofNullable(graph.get(key))
.map(Collections::unmodifiableCollection)
.orElse(Collections.EMPTY_SET);
}
You could also use a Guava Multimap if you aren't averse to external libraries.
Using a Multimap for your problem, it could be written like that:
public static void main(String[] args) {
PrintWriter pw=new PrintWriter(System.out);
ListMultimap<Vertex,Vertex> m= ArrayListMultimap.create();
Vertex a = new Vertex("a"); // it's better to create each object once
Vertex b = new Vertex("b");
Vertex c = new Vertex("c");
Vertex d = new Vertex("d");
m.put(a,b);// a ---> b
m.put(a,c);// a ---> c
m.put(a,d);// a ---> d
pw.println("All vertex from: ");
for (Vertex vert_from:m.keySet()) { //exactly the same as in your code
pw.print(vert_from+" ");
}
pw.println();
pw.println("All vertices to: ");
for (Vertex vert_to:m.values()) { //exactly the same as in your code
pw.print(vert_to+" ");
}
pw.close();
}
To use Guava, just download the latest jar from here and add it to your libraries.
Explanation:
By definition, each java Map has a single key and a single value.
However, you can use a Collection (like a List), or an Array for value. This way, your Map will be defined like that:
Map<Vertex, List<Vertex>> m = new HashMap<>();
Each time you want to add an element value to the list of vertex key, you can do it that way:
List<Vertex> list = m.get(key);
if (list == null) {
list = new ArrayList<>();
}
list.add(value);
An easier way, is to use Guava's Multimaps. It is the same as a Map, but the value is a Collection. So, an ArrayListMultimap is quite what I described above. The way to use it, though is much simpler:
ListMultimap<Vertex, Vertex> m = ArrayListMultimap.create();
m.put(key, value1);
m.put(key, value2); //adds value2 to the key, which also contains value1
....
Since Java doesn't allow passing methods as parameters, what trick do you use to implement Python like list comprehension in Java ?
I have a list (ArrayList) of Strings. I need to transform each element by using a function so that I get another list. I have several functions which take a String as input and return another String as output. How do I make a generic method which can be given the list and the function as parameters so that I can get a list back with each element processed. It is not possible in the literal sense, but what trick should I use ?
The other option is to write a new function for each smaller String-processing function which simply loops over the entire list, which is kinda not so cool.
In Java 8 you can use method references:
List<String> list = ...;
list.replaceAll(String::toUpperCase);
Or, if you want to create a new list instance:
List<String> upper = list.stream().map(String::toUpperCase).collect(Collectors.toList());
Basically, you create a Function interface:
public interface Func<In, Out> {
public Out apply(In in);
}
and then pass in an anonymous subclass to your method.
Your method could either apply the function to each element in-place:
public static <T> void applyToListInPlace(List<T> list, Func<T, T> f) {
ListIterator<T> itr = list.listIterator();
while (itr.hasNext()) {
T output = f.apply(itr.next());
itr.set(output);
}
}
// ...
List<String> myList = ...;
applyToListInPlace(myList, new Func<String, String>() {
public String apply(String in) {
return in.toLowerCase();
}
});
or create a new List (basically creating a mapping from the input list to the output list):
public static <In, Out> List<Out> map(List<In> in, Func<In, Out> f) {
List<Out> out = new ArrayList<Out>(in.size());
for (In inObj : in) {
out.add(f.apply(inObj));
}
return out;
}
// ...
List<String> myList = ...;
List<String> lowerCased = map(myList, new Func<String, String>() {
public String apply(String in) {
return in.toLowerCase();
}
});
Which one is preferable depends on your use case. If your list is extremely large, the in-place solution may be the only viable one; if you wish to apply many different functions to the same original list to make many derivative lists, you will want the map version.
The Google Collections library has lots of classes for working with collections and iterators at a much higher level than plain Java supports, and in a functional manner (filter, map, fold, etc.). It defines Function and Predicate interfaces and methods that use them to process collections so that you don't have to. It also has convenience functions that make dealing with Java generics less arduous.
I also use Hamcrest** for filtering collections.
The two libraries are easy to combine with adapter classes.
** Declaration of interest: I co-wrote Hamcrest
Apache Commons CollectionsUtil.transform(Collection, Transformer) is another option.
I'm building this project to write list comprehension in Java, now is a proof of concept in https://github.com/farolfo/list-comprehension-in-java
Examples
// { x | x E {1,2,3,4} ^ x is even }
// gives {2,4}
Predicate<Integer> even = x -> x % 2 == 0;
List<Integer> evens = new ListComprehension<Integer>()
.suchThat(x -> {
x.belongsTo(Arrays.asList(1, 2, 3, 4));
x.is(even);
});
// evens = {2,4};
And if we want to transform the output expression in some way like
// { x * 2 | x E {1,2,3,4} ^ x is even }
// gives {4,8}
List<Integer> duplicated = new ListComprehension<Integer>()
.giveMeAll((Integer x) -> x * 2)
.suchThat(x -> {
x.belongsTo(Arrays.asList(1, 2, 3, 4));
x.is(even);
});
// duplicated = {4,8}
You can use lambdas for the function, like so:
class Comprehension<T> {
/**
*in: List int
*func: Function to do to each entry
*/
public List<T> comp(List<T> in, Function<T, T> func) {
List<T> out = new ArrayList<T>();
for(T o: in) {
out.add(func.apply(o));
}
return out;
}
}
the usage:
List<String> stuff = new ArrayList<String>();
stuff.add("a");
stuff.add("b");
stuff.add("c");
stuff.add("d");
stuff.add("cheese");
List<String> newStuff = new Comprehension<String>().comp(stuff, (a) -> { //The <String> tells the comprehension to return an ArrayList<String>
a.equals("a")? "1":
(a.equals("b")? "2":
(a.equals("c")? "3":
(a.equals("d")? "4": a
)))
});
will return:
["1", "2", "3", "4", "cheese"]
import java.util.Arrays;
class Soft{
public static void main(String[] args){
int[] nums=range(9, 12);
System.out.println(Arrays.toString(nums));
}
static int[] range(int low, int high){
int[] a=new int[high-low];
for(int i=0,j=low;i<high-low;i++,j++){
a[i]=j;
}
return a;
}
}
Hope, that I help you :)