Path stack in a Java recursive search - java

I wrote a simple Depth-First search algorithm, which works, but is failing to build the patch right. Im having a tough time trying to understand, why - so, basically, need your help, guys :)
Here is the code:
public void Search(String from, String to) {
String depart = from;
String destin = to;
if ( (NoChildren(depart) == false)
&& (!depart.equalsIgnoreCase(destin)) ) {
while (!depart.equalsIgnoreCase(to)) {
closeStack.push(depart);
depart = getChildren(depart);
}
}
}
public boolean NoChildren(String from) {
boolean noChildren = false;
int counter = 0;
for(int j = 0; j < Flights.size(); j++) {
FlightInfo flight = (FlightInfo)Flights.elementAt(j);
if (flight.from().equalsIgnoreCase(from)) {
counter++;
}
}
if (counter == 0) {
noChildren = true;
}
return noChildren;
}
public String getChildren(String from) {
for(int j = 0; j < Flights.size(); j++) {
FlightInfo flight = (FlightInfo)Flights.elementAt(j);
if (flight.from().equalsIgnoreCase(from)) {
openStack.push(flight.to().toString());
}
}
return openStack.pop().toString();
}
I made it longer just for clearance, and planning to optimize it - just need to make it work properly first :))
Ok, the main problem is with that closeStack, which was meant to contain a path from start to finish - but now, it contains whatever the algorithm checked :-[
Thanx in advance!!

Maxim, there are a whole bunch of errors in your code. It looks as if you had an idea for what you wanted to do, and then threw some code at it until something emerged and worked a bit, but there's no clear concept here and thus it's no wonder it's not really working.
The core of this program is the Flights collection (why is Flights uppercased?), and it's very possible to build a working route finder around it. I'm not sure whether it would help you more to give you some hints or to simply build the program for you.
Update: I've meanwhile found a flight schedule for a Polish airline (don't ask!) with 203 distinct routings that I can use to fill and test a flight connection structure. I'm going to start hacking and we'll see how it goes.
Update: Here's the code.
To be at all useful for your apparent purpose, it's probably not enough to just find a routing (i.e. an itinerary of airports visited); you probably want a list of flights taken to get there. Note, of course, that there may be multiple combinations of flights that have the same itinerary - this code just finds the first.
You may want to modify the algorithm to place a weight (= cost) on travel time, if you have those, so your passengers get not just the smallest number of legs (= hops from one airport to the next) but also the shortest combined travel time. This more general form of the algorithm would be called Dijkstra's Algorithm, and is also described in Wikipedia.
Interestingly enough, it seems that BFS is not really suited to a recursive solution. Like your original code, my code is essentially imperative with a few loops. Note that the correct "main" data structure for doing BFS is not a stack but a queue!
public class Maxim {
/**
* Create a Maxim instance and run a search on it.
*/
public static void main(String[] args) {
try {
Maxim maxim = new Maxim();
Route r = maxim.findRoute("FCO", "DNV"); // tests a single origin/destination pair
if (r == null) {
System.out.println("No route found");
} else {
System.out.println(Arrays.deepToString(r.toArray()));
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* A simple Flight. Contains a flight number and only a single leg.
* number: Flight number
* dep: Departure airport
* arr: Arrival airport
*/
class Flight {
final String number, dep, arr;
public Flight(String number, String departure, String arrival) {
this.number = number; this.dep = departure; this.arr = arrival;
}
public String toString() {
return "Flight [number=" + this.number + ", dep=" + this.dep + ", arr=" + this.arr + "]";
}
}
/**
* Airport: A city and a list of Flights originating from it.
*/
class Airport {
public final String city;
public List<Flight> flights = new ArrayList<Flight>();
public Airport(String city) {
this.city = city;
}
public String toString() {
return "Airport [city=" + this.city + ", flights=" + this.flights + "]";
}
}
/**
* Route: A list of flights that get a traveller from a given origin to a destination.
*/
static class Route extends ArrayList<Flight> { }
/**
* Our known list of flights. It's not really needed after initialization.
*/
private List<Flight> flights = new ArrayList<Flight>();
/**
* List of airports. These constitute the graph we search.
*/
private Map<String, Airport> airports = new HashMap<String, Airport>();
/**
* Constructor. Constructs the "airports" graph from a list of "flights" read from a file.
*/
public Maxim() throws Exception {
// Read flights from file into list "flights".
// The file contains strings like " 696KGDWAW" = flight number, departure airport, arrival airport
BufferedReader flightReader = new BufferedReader(new FileReader("/home/carl/XX.flights"));
while (true) {
String flt = flightReader.readLine();
if (flt == null) break;
flights.add(new Flight(flt.substring(0,4), flt.substring(4, 7), flt.substring(7, 10)));
}
flightReader.close();
// Create a map of each airport to a list of Flights departing from it.
// This is the graph we'll be doing BFS on.
for (Flight flight : flights) {
String from = flight.dep;
if (!airports.containsKey(from)) {
Airport port = new Airport(from);
port.flights.add(flight);
airports.put(from, port);
} else {
Airport port = airports.get(from);
port.flights.add(flight);
}
}
}
/**
Algorithm (from Wikipedia):
1. Enqueue the root node.
2. Dequeue a node and examine it.
If the element sought is found in this node, quit the search and return a result.
Otherwise enqueue any successors (the direct child nodes) that have not yet been discovered.
3. If the queue is empty, every node on the graph has been examined – quit the search and return "not found".
4. Repeat from Step 2.
*/
public Route findRoute(String origin, String destination) {
Queue<Airport> queue = new LinkedList<Airport>();
Map<Airport, Flight> backtrack = new HashMap<Airport, Flight>();
Airport oriApt = this.airports.get(origin);
if (oriApt == null) return null; // origin airport not found - no solution
queue.add(oriApt);
while (!queue.isEmpty()) {
Airport apt = queue.remove();
if (apt == null) break;
if (apt.city.equals(destination)) { // Made it to destination; create the route and return it
Route toHere = new Route();
while (apt != oriApt) {
Flight flt = backtrack.get(apt);
toHere.add(flt);
apt = airports.get(flt.dep);
}
Collections.reverse(toHere);
return toHere;
}
// enqueue all new airports reachable from this airport.
// record the flight that got us there in backtrack.
for (Flight flt: apt.flights) {
Airport destApt = airports.get(flt.arr);
if (backtrack.containsKey(destApt)) continue; // we've been to this destination before - ignore
backtrack.put(destApt, flt);
queue.add(destApt);
}
}
// if we're here, we didn't find anything.
return null;
}
}

Related

Hash Structure in Java issues

Here is the HW problem:
At this point, you decide to implement a Hash structure for the contributor data to prepare for searches. You will read the contributor information from a file provided; it is a comma delimited (CSV) file. As each record is read, create a Hash table for the ID field. The limitation for the Hash table is that it has a size of 5, so you need to be able to handle collisions. Collisions should be resolved through the use of a linked list for the ID values (implement this using a stack). Your design should include the following:
A Hash table pointing to a structure for a linked list that contains only the following information:
Each Hash Bucket Collision Item will have the following Information:
ID: Integer; //identifier key for future needs
Hash Bucket Functions/Methods:
Input constructor: //to accept a string for the name and additional information for each contributor (you will only need the ID portion of the input data)
Hash Function constructor: (Hint: You only have 5 Hash buckets, so the function can be a very simple calculation.)
Pop constructor
Push constructor
Print constructor: //to show the contents of a Hash bucket
Deliverables:
A fully documented program to load the Hash table with collisions being handled as a linked list, implemented as a Stack
A test plan to show how the program runs and can be executed
A screenshot showing that the program loaded the data, and after all data is loaded, shows the contents of the first Hash bucket (ideally this is Bucket 0)
I believe I've gotten really close, but I'm used to Python so the Java syntax is something I'm trying to learn. Either way, check the code below to see what I've done.
I believe the problem has to do with the way I am declaring the hash table size. In python, I can just index the array and add a given object to that position in the array. Seems I can't do that in java though. I considered trying a for loop, but it didn't work
I feel like I'm pretty close. Most of the code was given from the professor, but I developed the Stack() class and methods on my own. When I run them they do work, and I got a 100% on that portion.
Through the debugging I've done, I can see that I am initializing an array of size 'size' (in this case 5). However, I can't figure out how to assign a key value pair to a given Stack() index.
Again, I'm used to Python and don't know much java, so I really think it's me not understanding Java syntax.
In python I would just do something along the lines of array[index].append[node]. Then, I could pop the array[index] and display the node one at a time.
import java.util.Scanner;
import java.io.File;
import java.util.regex.Pattern;
public class ContributorManager {
public static void main(String [] args) {
Scanner inputFile = null;
String name = null;
String city = null;
String country = null;
String phone = null;
double contribution = 0;
int id = 0;
Contributor c = null;
Node node = null;
HashTable h = new HashTable(5);
//open contributors file
try {
inputFile = new Scanner(new File("/Users/Dan/Desktop/contributors.csv"));
System.out.println("AsdasdfaDSF");
inputFile.useDelimiter(Pattern.compile("(\\n)|(\\r)|,"));
}
catch (Exception e) {
System.err.println("Error opening file.");
}
//create contributors object for each row, and add to the stack
while (inputFile.hasNext()) {
name = inputFile.next();
city = inputFile.next();
country = inputFile.next();
phone = inputFile.next();
contribution = inputFile.nextDouble();
id = inputFile.nextInt();
inputFile.nextLine(); //advance to the next line
c = new Contributor(name, city, country, phone, contribution, id);
node = new Node(c);
//System.out.println(c.hashFunction());
h.insert(node); //insert node into the hash table
}
h.print(); //print the entire hash table
}
}
public class Contributor {
private String name;
private String city;
private String country;
private String phone;
private double contribution;
private int id;
public Contributor(String name, String city, String country, String phone, double contribution, int id) {
this.name = name;
this.city = city;
this.country = country;
this.phone = phone;
this.contribution = contribution;
this.id = id;
}
public int hashFunction() {
//calculate the hash key value using the id member variable in this object
//the key must always return a value between 0 and 4
int key = this.id % 5;
return key;
//return the hash key value
}
public void printContributor() {
System.out.println("Name: " + name);
System.out.println("City: " + city);
System.out.println("Country: " + country);
System.out.println("Phone: " + phone);
System.out.println("Contribution: " + contribution);
System.out.println("ID: " + id);
System.out.println();
}
}
import java.util.LinkedList;
public class HashTable {
Stack[] table;
private int size;
private int top;
//declaring array
public HashTable(int size) {
//initialize the table array with empty Stack objects
table = new Stack[size];
System.out.println(table.length);
}
public void insert(Node n) {
//determine the hash key of Node n
System.out.println(n);
int key = n.c.hashFunction();
System.out.println(key);
//using the key to determine the table location,
//push Node n onto the stack
System.out.println(table.length);
table[key].push(n);
}
public void print() {
//display the contents of the entire table in order
for (int i=0; i < table.length; i++) {
System.out.println("===== Position " + i + " ======\n");
table[i].print();
System.out.println("========= End ==========");
System.out.println();
}
}
}
public class Node {
Contributor c;
Node next;
public Node(Contributor data){
//initialize member variables
c=data;
next=null;
}
public void displayNode() {
//display the contents of this node
c.printContributor();
}
}
public class Stack {
Node first;
public Stack(){
//initialize the empty stack
first = null;
}
public void push(Node newNode){
//if the stack is empty, make first point to new Node.
if(first==null)
first=newNode;
//if the stack is not empty, loop until we get to the end of the list,
//then make the last Node point to new Node
else
{
first=newNode;
newNode = newNode.next;
}
}
public Node pop() {
//if the stack is empty, return null
if(first==null)
return null;
//Handle the case where there is only one Node in the stack
else if(first.next==null)
{
Node t=first;
return t;
}
//Handle the case where there are at Least two (or more) elements in the stack
else
{
Node t=first;
return t;
}
}
public void print() {
//display the entire stack
Node tempDisplay = first; // start at the beginning of linkedList
while (tempDisplay != null){ // Executes until we don't find end of list.
tempDisplay.displayNode();
tempDisplay = tempDisplay.next;
}
System.out.println();
}
}
contributor.csv
Tim,Murphy,USA,8285557865,200,25
Gordon,Miner,USA,8285551008,150,32
Jean,Bell,USA,8285557503,225,33
Mike,Prather,USA,8285558497,155,34
George ,Pipps,USA,8285557777,100,35
However, I can't figure out how to assign a key value pair to a given Stack() index.
A stack is not an array. Index assignment is not a supported operation, only push and pop from one end of the structure.
It looks like you're having problems with the push and pop operations? Your code comments indicate what needs to be done. if stack is not empty, then loop to the end
You have no loop, and you seem to be inserting into the stack backwards.
Instead you'd probably want something like the following, very similar to the print method
Node n = first;
while (n.next != null) n = n.next;
n.next = newNode;
Similarly for popping, you'd stop the loop when n.next != null && n.next.next == null so that you can set n.next = null and pop it off the list
//TODO: loop logic
Node toPop = n.next;
n.next = null;
return toPop;

Looping over a huge list, check string equal to true

I have a requirement as below:
List<User> userList = listOfUsers(); // Morethan 50,000 users
I need to find a user status from the list of users. if any one of the users is active then break the loop.
what is the efficient way to handle this in java ?
Java 8 solution with method reference:
userList.stream().filter(User::isActive).findFirst()
It'll return Optional so you could map over it.
One way to accelerate the search (Without Using Java 8) is by searching both directions in the ArrayList (i.e from the beginning to the middle, and from the end to the middle) at the same time via using multi-threading, I created this example and tested it against 1 million object/user to check if any of them is active (Note that I made only one user active and put him in the middle to see the longest time the search may take).
import java.util.ArrayList;
public class User {
// some fields to test
String name;
boolean active;
//volatile means all writes up to the volatile variable
//from other any thread are now visible to all other threads.
//so they can share working on that variable
static volatile boolean finishFirst = false; // to announce first thread finish
static volatile boolean finishSecond = false; // to announce second thread finish
static volatile boolean found = false; // // to announce if an active user found
/**
* Simple Constructor
* #param name
* #param active
*/
public User(String name, boolean active){
this.name = name;
this.active = active;
}
public static void main(String[] args) {
// create an ArrayList of type User
ArrayList<User> list = new ArrayList<User>();
// populate it with 1 MILLION user!!
int i=0;
for(;i<1000000; i++){
// make only the one in the very middle active to prolong the search to max
if(i==500000){
list.add(new User(String.valueOf(i),true));
}
else{
list.add(new User(String.valueOf(i),false));
}
}
System.out.println("End of Adding " + i + " User" );
// to measure how long it will take
long startTime, endTime;
startTime = System.currentTimeMillis();
System.out.println("Found Any Active: "+ isAnyActive(list)); // invoke the method
endTime = System.currentTimeMillis();
System.out.println(endTime-startTime + " MilliScond");
}
public static boolean isAnyActive(ArrayList<User> list){
found = false;
// create two threads, each search the half of the array
// so that shall save time to half
Thread t1 = new Thread(new Runnable(){
#Override
public void run() {
// read one more index in case the size is not an even number
// so it will exceed the middle in one -> no problem at all
for(int i=0; i<=(list.size()/2)+1; i++){
if(list.get(i).active) {
found = true;
finishFirst = true;
break;
}
}
finishFirst = true; // in case did not find any
}
});
// second thread the same, but read from the end to the middle
Thread t2 = new Thread(new Runnable(){
public void run() {
for(int i=list.size()-1; i>=list.size()/2; i--){
if(list.get(i).active) {
found = true;
finishSecond = true;
break;
}
}
finishSecond = true;
}
});
// start both thread
t2.start();
t1.start();
// while one of them has not finished yet
while(!finishFirst || !finishSecond){
// but in case not finished looping but found an active user
// break the loop
if(found){break;}
}
return found; // return the result
}
}
Test
End of Adding 1000000 User
Found Any Active: true
31 MilliScond
The efficient way is to do that filter with SQL if you are using that. Select just the active users....
When you have all that list to work with java it will be slow as hell and there is no magic here, you will need to iterate.
public User getActiveUserFromList(userList) {
for (User user : userList) {
if (user.isActive()) {
return user;
}
return null;
}
}
If you have that list anyway ordered you can try to hack it, let's assume it is ordered by active status
public Boolean isAnyActive(userList) {
if (userList.first().isActive()) { // try first
return true;
}
if (userList.last().isActive()) { // if its ordered and there is an active user, the last surely will be active, since first wasn't
return true;
}
return false;
}
I would certainly think about using Java 8 Lambda. I have written an example class:
package com.chocksaway;
import java.util.ArrayList;
import java.util.List;
/**
* Author milesd on 05/06/2017.
*/
class Name {
private String name;
private Boolean status;
public Name(String name, Boolean status) {
this.name = name;
this.status = status;
}
public String getName() {
return name;
}
public Boolean getStatus() {
return status;
}
}
public class FindFirstInStream {
public static void main(String[] args) {
List<Name> userList = new ArrayList<>();
userList.add(new Name("James", false));
userList.add(new Name("Eric", true));
userList.add(new Name("David", false));
Name firstActiveName = userList.stream()
.filter(e -> e.getStatus().equals(true))
.findFirst()
.get();
System.out.println(firstActiveName.getName());
}
}
I've created a Name class, with name, and status.
I populate a userList with James, Eric, and David.
I use Java 8 stream to filter, and return the first "active" name (Eric).
This is stored in "firstActiveName".
You may use Collections ArrayDeque. ArrayDeques will use half of the iteration to find the active user. In your case
ArrayDeque sample = new ArrayDeque(userList);
for(int i=0;i<sample.size();i++){
if(sample.pollFirst().status.equalsIgnoreCase("A")) {
break;
}
if(sample.pollLast().status.equalsIgnoreCase("A")) {
break;
}
if(sample.size()==0) break;
}
Because I see many Java 8 streaming solutions that do not use parallel streams, I add this answer. You have a large collection on which you do the matching, so you can use the power of parallelStreams when you would opt to use Java 8.
Optional<User> result = userList.parallelStream().filter(User::isActive).findAny();
Using a parallelStream will split the stream into multiple sub-streams which is more performant for very large collections. It uses the ForkJoinPool internally to process these sub-streams. The only difference here is that I use findAny() instead of findFirst() in this solution.
This is what Javadoc has to say about findAny():
The behavior of this operation is explicitly nondeterministic; it is
free to select any element in the stream. This is to allow for maximal
performance in parallel operations; the cost is that multiple
invocations on the same source may not return the same result. (If a
stable result is desired, use findFirst() instead.)
Here is a nice tutorial on Parallelism from Oracle.

Parse many paths in the file tree object. Is there an efficient algorithm?

My code requires creation the file tree of the many file paths as
dir1/file1
dir1/dir2/file2
dir1/dir2/file3
FileTree object visualization example:
dir1
|_file1
|_dir2
|_file2
|_file3
This tree is used for torrent content files visualization in graphical form. It's also used for dynamically show files progress.
In a small number subfolders and files it works effectively, but if paths > 10,000 it takes a lot of memory and time (> 4 seconds and 50 MB RAM).
Is there an efficient algorithm for making such a graph? Most critical for me is the graph make speed.
An example of algorithm implementation can be written in any language, it doesn't matter for me :-)
Thanks in advance.
My Java code for this purpose:
FileTree root = new FileTree(FileTree.ROOT, File.Type.DIR);
FileTree parentTree;
for (String pathToFile : paths) {
parentTree = root;
String[] nodes = FileIOUtils.parsePath(pathToFile); /*String.split(File.separator)*/
for (int i = 0; i < nodes.length; i++) {
/* The last leaf item is a file */
if (i == (nodes.length - 1)) {
parentTree.addChild(new FileTree(nodes[i],
File.Type.FILE, parentTree));
} else {
parentTree.addChild(new FileTree(nodes[i], FileNode.Type.DIR, parentTree));
}
FileTree nextParent = parentTree.getChild(nodes[i]);
/* Skipping leaf nodes */
if (nextParent != null && !nextParent.isFile()) {
parentTree = nextParent;
}
}
}
FileTree class:
public class FileTree {
public static final String ROOT = "/";
/* The name for pointer to the parent node */
public static final String PARENT_DIR = "..";
protected String name;
protected boolean isLeaf;
protected FileTree parent;
protected Map<String, FileTree> children = new LinkedHashMap<>();
public FileTree(String name, int type, FileTree parent) {
this(name, type, parent);
}
public FileTree(String name, int type)
{
this(name, type, null);
}
public FileTree(String name, int type, FileTree parent)
{
this.name = name;
isLeaf = (type == File.Type.FILE);
this.parent = parent;
}
public synchronized void addChild(FileTree node)
{
if (!children.containsKey(node.getName())) {
children.put(node.getName(), node);
}
}
public boolean contains(String name)
{
return children.containsKey(name);
}
public F getChild(String name)
{
return children.get(name);
}
public Collection<FileTree> getChildren()
{
return children.values();
}
public Set<String> getChildrenName()
{
return children.keySet();
}
}
Edit:
It was possible to achieve the speed of creating tree of 1000 subfolders an average of 0.5-1 second (early 30 second).
FileTree root = new BencodeFileTree(FileTree.ROOT, 0L, File.Type.DIR);
FileTree parentTree = root;
/* It allows reduce the number of iterations on the paths with equal beginnings */
String prevPath = "";
/* Sort reduces the returns number to root */
Collections.sort(files);
for (String file : files) {
String path;
/*
* Compare previous path with new path.
* Example:
* prev = dir1/dir2/
* cur = dir1/dir2/file1
* |________|
* equal
*
* prev = dir1/dir2/
* cur = dir3/file2
* |________|
* not equal
*/
if (!prevPath.isEmpty() &&
file.regionMatches(true, 0, prevPath, 0, prevPath.length())) {
/*
* Beginning paths are equal, remove previous path from the new path.
* Example:
* prev = dir1/dir2/
* cur = dir1/dir2/file1
* new = file1
*/
path = file.substring(prevPath.length());
} else {
/* Beginning paths are not equal, return to root */
path = file;
parentTree = root;
}
String[] nodes = FileIOUtils.parsePath(path);
/*
* Remove last node (file) from previous path.
* Example:
* cur = dir1/dir2/file1
* new = dir1/dir2/
*/
prevPath = file.substring(0, file.length() - nodes[nodes.length - 1].length());
/* Iterates path nodes */
for (int i = 0; i < nodes.length; i++) {
if (!parentTree.contains(nodes[i])) {
/* The last leaf item is a file */
parentTree.addChild(makeObject(nodes[i], parentTree,
i == (nodes.length - 1)));
}
FileTree nextParent = parentTree.getChild(nodes[i]);
/* Skipping leaf nodes */
if (!nextParent.isFile()) {
parentTree = nextParent;
}
}
}
The basic algorithm looks good to me, but you are creating a lot of unnecessary FileTree objects when you call addChild that will be immediately thrown away in the (common) case they already exist. You could try passing in the parameters to the constructor and only construct the object if it needs to be inserted:
public synchronized void addChild(String name, int type, FileTree parent)
{
if (!children.containsKey(name)) {
children.put(name, new FileTree(name, type, parent));
}
}
and:
if (i == (nodes.length - 1)) {
parentTree.addChild(nodes[i], File.Type.FILE, parentTree);
} else {
parentTree.addChild(nodes[i], FileNode.Type.DIR, parentTree);
}
It might not be necessary to pass in parentTree: you can just construct it with this.
Another optimization could be to maintain the array of String objects (and associated FileTree nodes) from the previous path that you processed, and scan along until you find an entry that is different to the previous one before adding children.
I would suggest to replace LinkedHashMap with HashMap because first one consumes more memory. The main difference is that HashMap does not guaranty order of iteration over entries. But you could order children in GUI (probably you have some ordering setting anyway). Take a look at this question for some references.
Another suggestion would be to return actual child node from method addChild
public synchronized FileTree addChild(FileTree node) {
return children.putIfAbsent(node.getName(), node);
}
Then inside loop there is no need to call get on map again
FileTree nextParent = parentTree.addChild(...
And there is condition that looks unnecessary
if (nextParent != null && !nextParent.isFile()) {
parentTree = nextParent;
}
Looks like there will be no iteration in loop if current child is a file. So it could be safely replaced with
parentTree = parentTree.addChild(...
After suggestions loop body would look like
for(...) {
int type = if (i == (nodes.length - 1)) ? File.Type.FILE : FileNode.Type.DIR;
parentTree = parentTree.addChild(new FileTree(nodes[i], type, parentTree);
}

Check for multiple instances of same object in array

i am looking for a way to check if an array contains more than 1 instances of the same object. I've been looking around but can't seem to find anything in the javadoc nor stackoverflow.
I am creating a monopoly board game (or in danish, matador) where the fee from landing on one of the fields differs depending on how many of that type of field the player owns.
I have a list in my player class in which i put all the fields that the player buys:
public List<OwnableField> ownsList = new ArrayList<>();
public void buy(OwnableField ownable) {
pay(ownable.getPrice());
ownsList.add(ownable);
}
And then i have this method in the specific field class, in which i am working on an if statement to set the fee:
public int fee;
public int feeCalc(int diceScore) {
if(this.getOwner().ownsList.(whatever checks for duplicate object in array)){
fee = 200 * diceScore;
} else {
fee = 100 * diceScore;
}
return fee;
}
If you have a proper equals and hash code defined then you can use sets to achive that
List list = ...
if(new HashSet(list).size().equals(list.size()){
//same size
} else {
//there was a duplicated element
}
If you want to check for one specific object only you could do it with:
final Object someObject = ...
List list = ...
int size = FluentIterable.from(list).filter(new Predicate<Object>() {
#Override
public boolean apply(Object input) {
return input == someObject;
}
}).size();
if(size > 1) {
//there is a duplicated element
}
Or, if you are looking for an instance of a class, then try:
List list = ...
int size = FluentIterable.from(list).filter(Predicates.instanceOf(YourClass.class)).size();
if(size > 1) {
//there is a duplicated element
}

Adding a string to an arraylist through another arraylist's object's method

I am in the process of updating my game to Java, but the only minor bug I have left is this:
Every time a dead player's name is "added" to the dead player name list, it adds the Player object's hashcode instead.
EDIT: Here is a link to a zip folder with the source code:
https://dl.dropboxusercontent.com/u/98444970/KarmaSource.zip
The code in question is the two places where the line gets the player object and gets the object's name. When it is used in println, it works fine and prints the player's name. However, in the second part where it does the same thing, but it prints the hashcode of the player object instead of calling its get_name method and returning the String. I'm not sure if it has to do with the third part, where it adds the "name" to dead player list pdead.
If you'd like a link to the compiled version, let me know. It's compiled under JDK 7 Update 51 64-bit.
EDIT: I got it working, I was originally referencing the players list instead of the pdead list. Thanks to all who contributed to helping. If you still want the game, let me know and I'll put a download link :D
Answering your question:
This code is wrong:
if (karma.pdead.isEmpty())
{System.out.println("None");}
else
for (int index = 0;index < karma.pdead.size();index++)
System.out.println(pdead.get(index));
What is karma? Whatever that is, looks like you're referring to 2 different things there.
Try this:
if (pdead.isEmpty()) {
System.out.println("None");
} else {
for (String deadPlayer : pdead) {
System.out.println(deadPlayer);
}
}
Pretty sure this will work :)
Some further, constructive advice:
Your code is breaking pretty much all conventions/good-practices I know in Java. But I am here to help, not to criticize, so let's try to improve this code.
Never keep state in static fields. This is a recipe for causing memory leaks.
your main function won't even compile. Should look like this:
public static void main(String[] args)
Always wrap the body of for loops with braces.
Be consistent: if you open braces in a new line, then do it every time. NEVER write code on the same line as the opening bracket.
GOOD:
public void doSomething()
{
// body
}
GOOD:
public void doSomething() {
// body
}
BAD:
public void doSomething() {
// body
}
public void somethingOther()
{
// inconsistent!
}
public void terribleCode()
{ System.out.println("Never do this"); }
Do not use underscores to separate words. In Java, the favoured convention is to use camelCase. getName(), not get_name().
class names ALWAYS start with a capital letter, whereas variable names generally start with a lower-case letter.
if you're iterating over all items of a list, just use the forEach construct (shown above) not index navigation.
I wanted to check to see if there was some subtle syntax error, so I cut/paste your code into an editor and tried to massage it to get it running. After my massaging, I ran it and it ran fine. Here is the code I ran and the results I got:
Code:
import java.util.ArrayList;
public class Game {
private static ArrayList<Player> players = new ArrayList<Player>();
private static ArrayList<String> pdead = new ArrayList<String>();
public static void main(String[] args) {
// Some Test Data
Player p1 = new Player("George");
p1.setHp(10);
players.add(p1);
Player p2 = new Player("Bob");
p2.setHp(10);
players.add(p2);
// Print Current State of data
System.out.println("Current Players");
for(Player p: players) {
System.out.println(p.getName() + ": " + p.getHp());
}
System.out.println("Dead Players");
if (pdead.isEmpty()) {
System.out.println("None");
} else {
for (int index=0; index < pdead.size(); index++) {
System.out.println(pdead.get(index));
}
}
// Kill Bob
p2.setHp(0);
// Do work to add names to dead players data structure
for (int index2=0; index2 < players.size(); index2++) {
if ((players.get(index2).getHp() <= 0) && !(pdead.contains(players.get(index2).getName()))) {
pdead.add(players.get(index2).getName());
}
}
// Print Current State of data
System.out.println("Current Players");
for(Player p: players) {
System.out.println(p.getName() + ": " + p.getHp());
}
System.out.println("Dead Players");
if (pdead.isEmpty()) {
System.out.println("None");
} else {
for (int index=0; index < pdead.size(); index++) {
System.out.println(pdead.get(index));
}
}
}
}
class Player {
private String name = "";
private int hp = 0;
public Player(String n) {
name = n;
}
public String getName() {
return name;
}
public int getHp() {
return hp;
}
public void setHp(int h) {
hp = h;
}
}
Here are the results that code gives me:
javac Game.java
java Game
Current Players
George: 10
Bob: 10
Dead Players
None
Current Players
George: 10
Bob: 0
Dead Players
Bob

Categories