using iterator to go over list of hashmaps - java

I have a String exp, which I have to compare with the mapsList.
String exp = "nodeId=1&&name=Router||level=1";
List mapList = new ArrayList();
Map map = new HashMap();
map.put("nodeId","1");
map.put("name","Router");
map.put("level", "1");
Map map1 = new HashMap();
map1.put("nodeId","2");
map1.put("name","Router");
map1.put("level","2");
Map map2 = new HashMap();
map2.put("nodeId","3");
map2.put("name","Router");
map2.put("level","3");
mapList.add(map);
mapList.add(map1);
mapList.add(map2);
I take the exp and split into an array.
String delims = "[\\&&\\||\\=]+";
String[] token = exp.split(delims);
Then I divide the array into two smaller sub arrays. One for Keys and the other for values. After which I compare ...
if(map.keySet().contains(a1[0]) && map.keySet().contains(a1[1]) || map.keySet().contains(a1[2])){
if(map.values().contains(a2[0]) && map.values().contains(a2[1]) || map.values().contains(a2[2])){
System.out.println("Match\tMapKeys: "+map.keySet()+" Values: "+map.values());
}else{
System.out.println("No Match\t");
}
}
So my problem is I can do this for each map, but can't figure out how to implement it with iterator.
Can some1 push me in the right direction?
Thanks.

You really, really want to define an object to hold your data, instead of using HashMaps.
class Node {
private int id;
private String name;
private int level;
public Node(int id, String name, int level) {
this.id = id;
this.name = name;
this.level = level;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getLevel() {
return level;
}
}
now you populate the list like this
List<Node> nodeList = new ArrayList<Node>();
nodeList.add(new Node(1, "Router", 1));
nodeList.add(new Node(2, "Router", 2));
nodeList.add(new Node(3, "Router", 3));
and you could look for your match like this
String exp = "nodeId=1&&name=Router||level=1";
String delims = "[\\&&\\||\\=]+";
String[] token = exp.split(delims);
int id = Integer.parseInt(token[1]);
String name = token[3];
int level = Integer.parseInt(token[5]);
boolean match = false;
for (Node node : nodeList) {
if (node.getId() == id && node.getName().equals(name)
&& node.getLevel() == level) {
System.out.println("Match found: " + node);
match = true;
}
}
if (!match) {
System.out.println("No match");
}
which gives me the following output
Match found: Node#1391f61c
and the next step is to implement toString.
You should check out http://docs.oracle.com/javase/tutorial/java/concepts/ as it introduces objects and why they are useful.

Related

Binary Search Tree (BST) search method for string

i've built a BST that have elements of (country code(string), indicator code(string), indicator name(string) and ArrayList of Years(int) and values(string)).
I'm trying to figure out how to prompt the user to search by entering Indicator code and then the year which the output will be the value.
it would be much appreciated if you could show how to code the search method cause I've tried everything.
I've tried this in the BST class. but it doesn't feel right(?)
public void search(Indicator indicator, String searchTerm){
String str = (String)indicator.getICode();
int n1 = str.compareTo(searchTerm);
int n2 = searchTerm.compareTo(str);
if (str == null || str.equalsIgnoreCase(searchTerm)){
return str;
}
if (n1 > n2){
return search(indicator, searchTerm);
}
else if (n1 < n2){
return search(indicator, searchTerm);
}
}
this is my application class:
public class BigDataBST{
public static void main (String [] Args) throws IOException {
try{
BST bigdata = new BST();
MyData d1;
File inFile = new File ("Indicator.txt");
FileReader fr = new FileReader (inFile);
BufferedReader br = new BufferedReader(fr);
String str = br.readLine();
while(str != null ){
StringTokenizer st = new StringTokenizer(str,";");
ArrayList <MyData> data = new ArrayList();
String cCode = st.nextToken();
String iName = st.nextToken();
String iCode = st.nextToken();
for (int j = 0; j < 59; j++){
String v = st.nextToken();
int year = 1960 + j;
d1 = new MyData (year,v);
data.add(d1);
}
Indicator idct = new Indicator (cCode,iName,iCode,data);
bigdata.insertNode(idct);
str = br.readLine();
}
TreeNode class:
TreeNode left;
TreeNode right;
Indicator idct;
public TreeNode(Indicator id){
left = right = null;
idct = id;
}
indicator class:
private String cCode; //country code
private String iName; //indicator Name;
private String iCode; //indicator code;
public ArrayList <MyData> DataList;
public Indicator(){
cCode = null;
iName = null;
iCode = null;
DataList = null;
}
public Indicator(String cCode, String iName, String iCode,ArrayList <MyData> DataList){
this.cCode = cCode;
this.iName = iName;
this.iCode = iCode;
this.DataList = DataList;
}
//setter & getter method for attributes iCode,iName and cCode
//toString method
MyData class:
private int year;
private String value;
public MyData(){
year = 0;
value = null;
}
public MyData(int year, String value){
this.year = year;
this.value = value;
}
//setter & getter method for attributes year and value
//toString method
example of indicator.txt:
(from left: cCode; iName; iCode; values)
MYS; Employment in industry (% of total employment) (modeled ILO estimate); SL.IND.EMPL.ZS;
29,08600044;28,56900024;28,36300087;28,02300072;27,51600075;27,48699951;27,39800072;27,30500031
I think you don't know how to search in a Binary Search Tree. You can do this by going to each node and can use recursion to do so.
In your search() you are taking Indicator as a parameter, but actually you need to take TreeNode because every node has a data of type Indicator which you can access.
In your search() you are calling the search() again and again with same parameters which will not give you results ever. Moreover, you don't have a base case. That's not how recursion work. You will be getting a stackoverflowException(Hahaa, its funny because we are on StackOverFlow). Use this code instead:
public void search(string key)
{
searchHelper(key, root); // root node will be in Tree.java
}
public void searchHelper(string key, TreeNode current)
{
if(current == null)
{
System.out.println("\nCant find !");
return;
}
if(key.compareTo(current.idct.getICode()) < 0 )
searchHelper(key, current.left);
else if(key.compareTo(current.idct.getICode()) > 0)
searchHelper(key,current.right);
else
System.out.println("\n"+current.idct + "Found \n");
}

How to sort an ArrayList<String> using Comparator?

Hey guys I'm trying to make a scoreboard for my game and therefor I need to sort it. My input is DATE;LEVEL;SCORE and I want to sort it by the highest score, if it's equal by the highest level and if it's equal by the date.
My ArrayList:
ArrayList<String> test = new ArrayList<>();
test.add("16.06.2018;1;10");
test.add("16.06.2018;1;2");
test.add("16.06.2018;1;5");
test.add("16.06.2018;1;1");
test.add("16.06.2018;1;3");
test.add("16.06.2018;2;3");
test.add("15.06.2018;1;3");
test.add("17.06.2018;1;3");
should be sorted
[16.06.2018;1;10, 16.06.2018;1;5, 16.06.2018;2;3, 15.06.2018;1;3, 16.06.2018;1;3, 17.06.2018;1;3, 16.06.2018;1;2, 16.06.2018;1;1];
but I'm getting
[16.06.2018;1;5, 16.06.2018;2;3, 15.06.2018;1;3, 16.06.2018;1;3, 17.06.2018;1;3, 16.06.2018;1;2, 16.06.2018;1;10, 16.06.2018;1;1]
My code:
Collections.sort(test, new Comparator<String>() {
#Override
public int compare(String A, String B) {
String[] tmp = A.split(";");
String[] tmp2 = B.split(";");
if (tmp[2].equals(tmp2[2])) {
if (tmp[1].equals(tmp2[1])) {
return compareDate(tmp[0], tmp2[0]);
} else {
return tmp2[1].compareTo(tmp[1]);
}
} else {
return tmp2[2].compareTo(tmp[2]);
}
}
//compares 2 dates
private int compareDate(String A, String B) {
String[] tmp = A.split("\\.");
String[] tmp2 = B.split("\\.");
if (tmp[2].equals(tmp2[2])) {
if (tmp[1].equals(tmp2[1])) {
return tmp[0].compareTo(tmp2[0]);
} else {
return tmp[1].compareTo(tmp2[1]);
}
} else {
return tmp[2].compareTo(tmp2[2]);
}
}
});
You're using a string-based lexical comparison which treats "5" as being greater than "10" (because the character '5' comes after '1' in the Unicode table).
Instead you should use a numerical comparison. Convert the strings to integers and compare them with Integer.compare or similar:
Instead of this:
return tmp2[2].compareTo(tmp[2]);
You can do this:
return Integer.compare(
Integer.parseInt(tmp2[2]),
Integer.parseInt(tmp[2])
);
If you are using Java 8, I would like to create an Object from that String so you can compare it easily :
test.stream()
.map(c -> {
String[] tmp = c.split(";");
MyObject obj = new MyObject(
LocalDate.parse(tmp[0], DateTimeFormatter.ofPattern("dd.MM.yyyy")),
Integer.valueOf(tmp[1]), Integer.valueOf(tmp[2])
);
return obj;
}).sorted(
Comparator.comparing(MyObject::getDate)
.thenComparing(MyObject::getLevel)
.thenComparing(MyObject::getScore));
With this Object :
class MyObject {
private LocalDate date;
private Integer level;
private Integer score;
public MyObject(LocalDate date, Integer level1, Integer score) {
this.date = date;
this.level = level;
this.score= score;
}
public MyObject() {
}
//getter setter
}
Or without an Object :
test.stream().map(c -> c.split(";")).sorted(
Comparator.comparing(a -> LocalDate.parse(((String[]) a)[0], DateTimeFormatter.ofPattern("dd.MM.yyyy")))
.thenComparing(a -> Integer.valueOf(((String[]) a)[1]))
.thenComparing(a -> Integer.valueOf(((String[]) a)[2])));
Note : You can put them in the order you want so you will get the expected result
I like the approach from #YCF_L and how #jspcal gets right to the point. I would usually break it up into reusable components like this.
public static void sort(List<String> data) {
Collections.sort(data, new DataComparator());
}
private static class DataComparator implements Comparator<String>
{
#Override
public int compare(String str1, String str2) {
DataObject data1 = DataObject.valueOf(str1);
DataObject data2 = DataObject.valueOf(str2);
return data1.compareTo(data2);
}
}
private static class DataObject implements Comparable<DataObject>
{
private static final Map<String,DataObject> valuesCache = new HashMap<String,DataObject>();
private LocalDate date;
private int value1;
private int value2;
/**
* Parse the "date;value1;value2" String into an Object.
* #param value the string
* #throws ParseException if the date is invalid
*/
public DataObject(String value) {
String[] values = value.split(";");
this.date = LocalDate.parse(values[0], DateTimeFormatter.ofPattern("dd.MM.yyyy"));
this.value1 = Integer.valueOf(values[1]);
this.value2 = Integer.valueOf(values[2]);
}
/**
* Parse the String into an object.
* #param str the string
* #return the data object
*/
public static DataObject valueOf(String str) {
DataObject data = valuesCache.get(str);
if (data == null) {
data = new DataObject(str);
valuesCache.put(str, data);
}
return data;
}
/**
* Compare this DataObject to the other DataObject.
*/
#Override
public int compareTo(DataObject other) {
int cmp = 0;
if (this != other) {
// first compare the value2 integers
// sort descending (higher first) by multiplying by -1
cmp = -1 * Integer.compare(this.value2, other.value2);
// if those values matched, then compare value1 integers
// also sort descending
if (cmp == 0) {
cmp = -1 * Integer.compare(this.value1, other.value1);
}
// if those values matched, then compare dates ascending
if (cmp == 0) {
cmp = this.date.compareTo(other.date);
}
}
return cmp;
}
#Override
public String toString() {
return String.format("%s;%d;%d", date, value1, value2);
}
}

Build a sorted list based on multiple parameters?

I have three arrays
String[] persons = {"jack","james","hill","catnis","alphonso","aruba"};
int[] points = {1,1,2,3,4,5};
int[] money = {25,66,24,20,21,22};
The nth position in all three arrays belong to the same entity, for eg:-
persons[0] == points[0] == money[0] i.e jack has 1 point and 25 bucks.
I want to build a list that sorts person alphabetically(ascending) , if the starting letter is same , then it should check points(descending) and if those are same too then it must check the money(descending).
The final list after sorting should be {aruba , alphonso , catnis , hill , james , jack}.
So I think you want something like this:
public class Person {
String name;
int points;
int money;
public Person(String name, int points, int money) {
this.name = name;
this.points = points;
this.money = money;
}
// getters
}
Then create a List<Person> with the data you have (e.g., new Person("jack", 1, 25)). And then sort them:
Collections.sort(persons, (person1, person2) -> {
// could be written more concisely, but this should make things clear
char letter1 = person1.getName().charAt(0);
char letter2 = person2.getName().charAt(0);
if (letter1 != letter2) {
return letter1 - letter2;
}
int points1 = person1.getPoints();
int points2 = person2.getPoints();
if (points1 != points2) {
return points2 - points1; // notice the order is reversed here
}
int money1 = person1.getMoney();
int money2 = person2.getMoney();
if (money1 != money2) {
return money2 - money1;
}
return 0; // unless you want to do something fancy for tie-breaking
});
That will give you a sorted List<Person> according to your criteria.
If you're up to something quick and dirty:
Comparator<Integer> cName = (i, j) -> Character.compare( persons[i].charAt(0), persons[j].charAt(0));
Comparator<Integer> cPoints = (i, j) -> Integer.compare( points[i], points[j]);
Comparator<Integer> cMoney = (i, j) -> Integer.compare( money[i], money[j]);
List<String> l =
IntStream.range(0, persons.length).boxed()
.sorted( cName.thenComparing(cPoints.reversed()).thenComparing(cMoney.reversed()) )
.map( i -> persons[i] )
.collect(Collectors.toList());
System.out.println(l);
The first 3 lines use lambdas to define comparators based on arrays indexes.
The following line uses streams:
Create an int stream of indexes from 0 to persons.length-1
Sort indexes of the stream based on the sequence of comparators
Map sorted indexes to person names
Collect it into a List
Ain't lambda and streams cool?
If you can have a Person model:
final class Person {
private final String name;
private final int points;
private final int money;
public Person(final String name, final int points, final int money) {
this.name = name;
this.points = points;
this.money = money;
}
// getters and setters (if you want)
#Override
public String toString() {
final StringBuffer sb = new StringBuffer("Person {")
.append("name=")
.append(name)
.append(", points=")
.append(points)
.append(", money=")
.append(money)
.append('}');
return sb.toString();
}
}
Then you could do something like this:
public static void main(final String... args) throws Exception {
Person[] persons = new Person[6]; // Use a List (if you can)
persons[0] = new Person("jack", 1, 25);
persons[1] = new Person("james", 1, 66);
persons[2] = new Person("hill", 2, 24);
persons[3] = new Person("catnis", 3, 20);
persons[4] = new Person("alphonso", 4, 21);
persons[5] = new Person("aruba", 5, 22);
System.out.printf("persons = %s%n%n", Arrays.toString(persons));
System.out.printf("Person[0] = %s%n%n", persons[0]);
Collections.sort(Arrays.asList(persons), (c1, c2) -> {
final int charComp = Character.compare(c1.name.charAt(0), c2.name.charAt(0));
if (0 == charComp) {
final int pointsComp = Integer.compare(c2.points, c1.points);
if (0 == pointsComp) { return Integer.compare(c2.money, c1.money); }
return pointsComp;
}
return charComp;
});
// The collection was modified at this point because of the "sort"
System.out.printf("persons = %s%n", Arrays.toString(persons));
}
Results:
persons = [Person {name=jack, points=1, money=25}, Person {name=james,
points=1, money=66}, Person {name=hill, points=2, money=24}, Person
{name=catnis, points=3, money=20}, Person {name=alphonso, points=4,
money=21}, Person {name=aruba, points=5, money=22}]
Person[0] = Person {name=jack, points=1, money=25}
persons = [Person {name=aruba, points=5, money=22}, Person
{name=alphonso, points=4, money=21}, Person {name=catnis, points=3,
money=20}, Person {name=hill, points=2, money=24}, Person {name=james,
points=1, money=66}, Person {name=jack, points=1, money=25}]
A more compact sort (but a little bit less efficient since you have to run all comparisons upfront):
Collections.sort(Arrays.asList(persons), (c1, c2) -> {
final int names = Character.compare(c1.name.charAt(0), c2.name.charAt(0));
final int points = Integer.compare(c2.points, c1.points);
final int money = Integer.compare(c2.money, c1.money);
return (0 == names) ? ((0 == points) ? money : points) : names;
});
Similar to EvanM's answer, you should group the three pieces of data into a single class.
public class Person {
private String name;
public String getName() { return name; }
private int points;
public int getPoints() { return points; }
private int money;
public int getMoney() { return money; }
}
Then you could sort them like so:
List<Person> persons = ...;
persons.sort(Comparator
.comparing(p -> p.getName().charAt(0))
.thenComparing(Comparator.comparing(Person::getPoints).reversed())
.thenComparing(Comparator.comparing(Person::getMoney) .reversed())
);

Creating node with weight in java graph

I am creating a program to create a graph for bibliography dataset. The graph is directed, has Author node and Paper node, and has 2 types of edges (author to paper edge, paper to paper edge).
I want to get an input from you about whether or not what I am creating is making sense. Right now, it produces the right result when I want to get the outEdge and inEdge from and to a node. But im not sure if this implementation is correct in terms of the methods, designs, and algorithm.
Also, I have a problem with assigning weight to a node. I want to ask how can I do this as well. Right now, what I have tried is as follows:
for (String item : CandidateAuthorType1Unique) {
double weight = Collections.frequency(CandidateAuthorType1, item);
n.setWeight(item,weight);;
System.out.println(n.getName() + " : " + n.getWeight());
}
However, after using setWeight, the getName() method returns null. This means that the weight assigned is not assigned to a certain item. I wonder how to update the weight a certain item.
If I use
for (String item : CandidateAuthorType1Unique) {
double weight = Collections.frequency(CandidateAuthorType1, item);
n = new Node(item,weight);
System.out.println(n.getName() + " : " + n.getWeight());
}
Does it mean that each time a new node n is created, the old n node will not be stored? How can I checked every node ever created and its weight?
I would like to ask for your input to this program. Any input would be really helpful for me. Thank you.
Main class: Ranker.java
import java.util.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.sql.*;
public class Ranker {
static Graph g;
static Node n;
static Edge e;
static HashMap nodeMap; // maps Integer NodeIDs to Node object
String id;
double weight;
Ranker() {
g = new Graph();
nodeMap = new HashMap();
n = new Node(id,weight);
}
public static void main (String[] args) throws ClassNotFoundException, SQLException, IOException, IllegalArgumentException, IllegalAccessException{
Ranker Ranker = new Ranker();
Connection connect = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
HashMap nodeMap = new HashMap(); // maps Integer NodeIDs to Node objects
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager.getConnection("jdbc:mysql://localhost/arnetminer?"+"user=root&password=1234");
preparedStatement = connect.prepareStatement("Select fr,t,ty from subedge");
resultSet = preparedStatement.executeQuery();
int i=0;
while(resultSet.next()) {
g.addEdgeForIndexing(resultSet.getInt(1),resultSet.getInt(2),resultSet.getInt(3));
i++;
System.out.println( "edges added to G = "+i);
}
System.out.println("Loaded " + g.nodeCount() + " nodes.");
buildNodes();
System.out.println("Enter first author key:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String authorkey1 = br.readLine();
int authorID1 = Integer.parseInt(authorkey1);
String AuthorID1 = "A"+authorID1;
ArrayList<String> p1 = g.getOutEdgesToP(AuthorID1);
System.out.println("P1 = " + p1);
ArrayList<String> p2 = new ArrayList<String>();
for (int j = 0; j<p1.size();j++){
ArrayList<String> temp = g.getOutEdgesToP(p1.get(j));
if (temp!=null)
p2.addAll(temp);
}
System.out.println("P2 = " +p2);
ArrayList<String> CandidateAuthorType1 = new ArrayList<String>();
for (int k = 0; k<p2.size(); k++){
ArrayList<String> temp = g.getInEdgesFromPtoA(p2.get(k));
if(temp!=null)
CandidateAuthorType1.addAll(temp);
}
System.out.println("Candidate Author Type 1= " + CandidateAuthorType1);
ArrayList<String> CandidateAuthorType1Unique = removeDuplicates(CandidateAuthorType1);
System.out.println("-----------------------------------------------");
System.out.println("Candidate author type 1 and author node weight:");
for (String item : CandidateAuthorType1Unique) {
double weight = Collections.frequency(CandidateAuthorType1, item);
n.setWeight(item,weight);;
System.out.println(n.getName() + " : " + n.getWeight());
}
ArrayList<String> CandidatePaperType1 = new ArrayList<String>();
for (int l = 0; l<CandidateAuthorType1.size(); l++){
ArrayList<String> temp = g.getOutEdgesToP(CandidateAuthorType1.get(l));
if(temp!=null)
CandidatePaperType1.addAll(temp);
}
System.out.println("Candidate Paper Type 1= " + CandidatePaperType1);
}
private static ArrayList<String> removeDuplicates(ArrayList<String> element){
ArrayList<String> result = new ArrayList<>();
HashSet<String> set = new HashSet<>();
for (String item : element) {
if (!set.contains(item)) {
result.add(item);
set.add(item);
}
}
return result;
}
private static void buildNodes()
{
String nodeID;
double weight = 0;
Node n;
Iterator it = g.nodeIteratorInitial();
while (it.hasNext()) {
nodeID = (String) it.next();
if (!nodeMap.containsKey(nodeID)){
n = new Node(nodeID,weight);
nodeMap.put(nodeID, 0);
}
}
}
}
Graph.java
import java.lang.reflect.Field;
import java.util.*;
public class Graph {
private HashSet<String> nodeIDs;
public HashMap<Integer, String> nodeIDsWithTN;
public HashMap<Integer, String> TNMap;
private HashMap<String, ArrayList<String>> edges;
private HashMap<String, ArrayList<String>> reverse;
private int numNodes;
private int numEdges;
private int numReverse;
public Graph() {
edges = new HashMap<String, ArrayList<String>>();
reverse = new HashMap<String, ArrayList<String>>();
nodeIDs = new HashSet<String>();
nodeIDsWithTN = new HashMap<Integer, String>();
TNMap = new HashMap<Integer, String>();
new HashSet();
}
public void addEdgeForIndexing(int from, int to, int T) throws IllegalArgumentException, IllegalAccessException {
String From = ""+from;
String To = ""+to;
int type = T;
if(T==1)
{
From="A"+from;
To="P"+to;
}
else if(T==2)
{
From="P"+from;
To="P"+to;
}
else
System.out.println("T ="+T+" value undefined");
Edge e = new Edge(From,To,type);
nodeIDs.add(e.From);
nodeIDs.add(e.To);
ArrayList<String> tmp = null;
if (edges.containsKey(e.From))
tmp = (ArrayList<String>) edges.get(e.From);
else {
tmp = new ArrayList<String>();
edges.put(e.From,tmp);
}
tmp.add(e.To);
ArrayList<String> tmp2 = null;
if (reverse.containsKey(e.To))
tmp2 = (ArrayList<String>) reverse.get(e.To);
else {
tmp2 = new ArrayList<String>();
reverse.put(e.To,tmp2);
}
tmp2.add(e.From);
}
public int nodeCount() {
if(nodeIDs.size() > 0)
return nodeIDs.size();
// else return numNodes;
return numEdges;
}
public int countInEdges(Integer key) {
if (!reverse.containsKey(key)) return 0;
return ((ArrayList<?>) reverse.get(key)).size();
}
public int countOutEdges(Integer key) {
if (!edges.containsKey(key)) return 0;
return ((ArrayList<?>) edges.get(key)).size();
}
public ArrayList<String> getInEdgesFromPtoA(String id) {
if (!reverse.containsKey(id)) return null;
ArrayList<String> a = reverse.get(id);
ArrayList<String> result = new ArrayList<String>();
for(int j=0;j<a.size();j++){
if(a.get(j).startsWith("A")){
result.add(a.get(j));
}
}
return result;
}
public ArrayList<String> getOutEdgesToP(String id) {
if (!edges.containsKey(id)) return null;
ArrayList<String> a = edges.get(id);
ArrayList<String> result = new ArrayList<String>();
for(int j=0;j<a.size();j++){
if(a.get(j).startsWith("P")){
result.add(a.get(j));
}
}
return result;
}
public Iterator<String> nodeIteratorInitial() {
return nodeIDs.iterator();
}
}
Edge.java
public class Edge {
String From;
String To;
int type;
private static int counter = 0;
public Edge(String From, String To, int type) {
this.From = new String(From);
this.To = new String(To);
this.type = type;
// System.out.println("edges added from " + From + " to " + To + " with type "+ type);
}
public String getFrom(){
return From;
}
public String getTo(){
return To;
}
public int getType(){
return type;
}
public void setFrom(String From){
this.From = From;
}
public void setTo(String To){
this.To = To;
}
public void setType(int type){
this.type = type;
}
}
Node.java
public class Node {
String id;
double weight;
private static int counter = 0;
public Node(String id,double weight) {
this.id = id;
this.weight = weight;;
}
public double getWeight(){
return weight;
}
public String getName() {
return id;
}
public void setWeight(String id, double weight){
if (this.id==id){
this.weight=weight;}
System.out.println("The node " + id + " has weight " + weight);
}
public void setName(String id){
this.id=id;
}
}
As you are initialising n in the Ranker() constructor, when the constructor is called, the String id has not been assigned and therefore always contains the value null. Therefore your Node n also gets the id as null. This is the reason why the weight isn't updated as in your setWeight(String id, double weight) function, the new id is compared to null which always returns false therefore the weight doesn't get updated.
You could make the following changes in your code
1) Remove the n = new Node(id,weight) initialisation in your Ranker() constructor.
2) Add the following lines instead of n.setWeight(item,weight) in your main method in Ranker class.
if (n == null)
n = new Node(item, weight);
n.setWeight(item, weight);

How to get N most often words in given text, sorted from max to min?

I have been given a large text as input. I have made a HashMap that stores each different word as a key, and number of times that occurs as value (Integer).
Now I have to make a method called mostOften(int k):List that return a List that gives the first k-words that from max number of occurrence to min number of occurrence ( descending order ) using the HashMap that I have made before.
The problem is that whenever 2 words have the same number of occurrence, then they should be sorted alphabetically.
The first idea that was on my mind was to swap keys and values of the given HashMap, and put it into TreeMap and TreeMap will sort the words by the key(Integer - number of occurrence of the word ) and then just pop the last/first K-entries from the TreeMap.
But I will have collision for sure, when the number of 2 or 3 words are the same. I will compare the words alphabetically but what Integer should I put as a key of the second word comming.
Any ideas how to implement this, or other options ?
Hints:
Look at the javadocs for the Collections.sort methods ... both of them!
Look at the javadocs for Map.entries().
Think about how to implement a Comparator that compares instances of a class with two fields, using the 2nd as a "tie breaker" when the other compares as equal.
Here's the solution with I come up.
First you create a class MyWord that can store the String value of the word and the number of occurences it appears.
You implement the Comparable interface for this class to sort by occurences first and then alphabetically if the number of occurences is the same
Then for the most often method, you create a new List of MyWord from your original map. You add the entries of this to your List
You sort this list
You take the k-first items of this list using subList
You add those Strings to the List<String> and you return it
public class Test {
public static void main(String [] args){
Map<String, Integer> m = new HashMap<>();
m.put("hello",5);
m.put("halo",5);
m.put("this",2);
m.put("that",2);
m.put("good",1);
System.out.println(mostOften(m, 3));
}
public static List<String> mostOften(Map<String, Integer> m, int k){
List<MyWord> l = new ArrayList<>();
for(Map.Entry<String, Integer> entry : m.entrySet())
l.add(new MyWord(entry.getKey(), entry.getValue()));
Collections.sort(l);
List<String> list = new ArrayList<>();
for(MyWord w : l.subList(0, k))
list.add(w.word);
return list;
}
}
class MyWord implements Comparable<MyWord>{
public String word;
public int occurence;
public MyWord(String word, int occurence) {
super();
this.word = word;
this.occurence = occurence;
}
#Override
public int compareTo(MyWord arg0) {
int cmp = Integer.compare(arg0.occurence,this.occurence);
return cmp != 0 ? cmp : word.compareTo(arg0.word);
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + occurence;
result = prime * result + ((word == null) ? 0 : word.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyWord other = (MyWord) obj;
if (occurence != other.occurence)
return false;
if (word == null) {
if (other.word != null)
return false;
} else if (!word.equals(other.word))
return false;
return true;
}
}
Output : [halo, hello, that]
In addition to your Map to store word counts I would use a PriorityQueue of fixed size K (with natural order). It will allow to reach O(N) complexity. Here is a code which use this approach:
In constructor we are reading input stream word by word filling the counters in the Map.
In the same time we are updating priority queue keeping it's max size = K (we need count top K words)
public class TopNWordsCounter
{
public static class WordCount
{
String word;
int count;
public WordCount(String word)
{
this.word = word;
this.count = 1;
}
}
private PriorityQueue<WordCount> pq;
private Map<String, WordCount> dict;
public TopNWordsCounter(Scanner scanner)
{
pq = new PriorityQueue<>(10, new Comparator<WordCount>()
{
#Override
public int compare(WordCount o1, WordCount o2)
{
return o2.count-o1.count;
}
});
dict = new HashMap<>();
while (scanner.hasNext())
{
String word = scanner.next();
WordCount wc = dict.get(word);
if (wc == null)
{
wc = new WordCount(word);
dict.put(word, wc);
}
if (pq.contains(wc))
{
pq.remove(wc);
wc.count++;
pq.add(wc);
}
else
{
wc.count++;
if (pq.size() < 10 || wc.count >= pq.peek().count)
{
pq.add(wc);
}
}
if (pq.size() > 10)
{
pq.poll();
}
}
}
public List<String> getTopTenWords()
{
Stack<String> topTen = new Stack<>();
while (!pq.isEmpty())
{
topTen.add(pq.poll().word);
}
return topTen;
}
}

Categories