I am trying to find the longest possible path based on how many connections a variable number has, without repeating connections. The way I thought of doing this was creating a list that holds all points that have already been gone through, but when a path ends, and I need to check a new path, all of those old connections remain in the list. How can I restart my list from the initial point?
Putting it in the recursive function itself would just clear the list each time. Is there a better option than using a list?
Relevant code:
package testapp;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.IOException;
import java.util.List;
class TestApp {
// Store list of objects we have already matched with
static List<NumberObject> holdingList = new ArrayList<NumberObject>();
//Test objects
static int[] array1 = {2,2};
static int[] array2 = {3,1};
static int[] array3 = {2,1};
static int[] array4 = {1,1};
static NumberObject eight = new NumberObject(array1, 8);
static NumberObject two = new NumberObject(array2, 2);
static NumberObject three = new NumberObject(array3, 3);
static NumberObject four = new NumberObject(array4, 4);
// Test objects ^^
public static int longestSequence(int[][] grid) {
// TODO: implement this function
// Code exists here not relevant to the problem
//Setting up a new numberList array for testing
NumberObject[] newNumberList = {eight, two, three, four};
NumberObject[] connections1 = {two, four};
NumberObject[] connections2 = {two, three};
//Adding connections
eight.connections = connections1;
four.connections = connections2;
for (NumberObject s: newNumberList){
recursive(s);
}
return 0;
}
public static void recursive(NumberObject object){
for (NumberObject x: holdingList){
System.out.println(x);
}
if (!holdingList.contains(object)){
holdingList.add(object);
if (object.hasConnections()){
NumberObject[] newobject = object.getConnections();
for(NumberObject y: newobject){
recursive(y);
}
}
else {
System.out.println(holdingList.size());
return;
}
}
else {
System.out.println(holdingList.size());
return;
}
}
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int numRows = 0;
int numCols = 0;
String[] firstLine = reader.readLine().split("\\s+");
numRows = Integer.parseInt(firstLine[0]);
numCols = Integer.parseInt(firstLine[1]);
int[][] grid = new int[numRows][numCols];
for (int row = 0; row < numRows; row++) {
String[] inputRow = reader.readLine().split("\\s+");
for (int col = 0; col < numCols; col++) {
grid[row][col] = Integer.parseInt(inputRow[col]);
}
}
int length = longestSequence(grid);
System.out.println(length);
}
}
class NumberObject {
int[] id;
int value;
NumberObject[] connections;
//Constructor
public NumberObject(int[] id, int value){
this.id = id;
this.value = value;
}
//print statement
public String toString(){
return ("NumberOject: Id = " + id + "\nValue = " + value);
}
//Check if it has connections
public boolean hasConnections(){
if (connections == null){
return false;
}
else if (connections.length != 0){
return true;
}
else
return false;
}
//Return the connections it has
public NumberObject[] getConnections(){
return connections;
}
}
Ideally, the image displays what I want to happen.
Instead, all the old branching connections remain on holdingList.
it should be noted paths can branch off to more than two other objects.
Instead of storing the list in a field, you could just pass an instance of a copy of your list to the function as an argument. So the signature of your function recursive would look like:
public static void recursive(NumberObject object, List<NumberObject> visited)
To hide this implementation detail, I recommend writing two functions, whereby the second function just passes an empty list to the other one.
However, I'd choose a different approach since yours acquires as many new lists as entries are in your tree. In the following implementation, you only have one list per "tree end". Moreover, just like in the previous suggestion, this keeps your class stateless.
static List<NumberObject> findLongestPath(NumberObject currentNode) {
if (currentNode.getConnectedNodes().isEmpty()) {
List<NumberObject> result = new ArrayList<>();
result.add(currentNode);
return result;
}
List<NumberObject> longestPath = currentNode.getConnectedNodes().stream()
.map(PathFinder::findLongestPath)
.max(Comparator.comparing(List::size))
.get();
longestPath.add(currentNode);
return longestPath;
}
Related
I have an arraylist that looks like this:
public static ArrayList<ArrayList<String[]>> x = new ArrayList<>();
I store groups of 2 persons in a pair. For example:
[Person1, Person2]
[Person3, Person4]
The algorithm I use right now still makes duplicates, I've tried out hashmaps and iterating through them with for loop but they just give me back the original list.
This is the code:
package com.company;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
public class createGroups
{
public static ArrayList<ArrayList<String[]>> x = new ArrayList<>();
public static void main(String[] args){
//Define names
String[] names = {"Person1", "Person2", "Person3", "Person4"};
try
{
//Create combinations. In a try catch because of the saveFile method.
combination(names, 0, 2);
//Print all the pairs in the Arraylist x
printPairs();
} catch (IOException e)
{
e.printStackTrace();
}
}
static void combination(String[] data, int offset, int group_size) throws IOException
{
if(offset >= data.length)
{
//Create new Arraylist called foo
ArrayList<String[]> foo = new ArrayList<>();
//Create a pair of 2 (data.length = 4 / group_size = 2)
for(int i = 0; i < data.length / group_size; i++)
{
//Add the pair to foo.
foo.add(Arrays.copyOfRange(data, 2 * i, 2 * (i + 1)));
}
//Add foo to x
x.add(foo);
//saveFile(foo);
}
for(int i = offset; i < data.length; i++){
for(int j = i + 1; j < data.length; j++){
swap(data, offset, i);
swap(data, offset + 1, j);
combination(data, offset + group_size, group_size);
swap(data, offset + 1, j);
swap(data, offset, i);
}
}
}
public static void printPairs(){
//Print all pairs
for(ArrayList<String[]> q : x){
for(String[] s : q){
System.out.println(Arrays.toString(s));
}
System.out.println("\n");
}
}
private static void swap(String[] data, int a, int b){
//swap the data around.
String t = data[a];
data[a] = data[b];
data[b] = t;
}
}
The output right now is this:
Output
Every group of 4 names is a 'list' of pairs (Not really a list but that's what I call it)
And this is the desired output:
Desired output
But then you can see that the first and the last list of pairs are basically the same how do I change that in my combination method
The question:
How can I change my combination method so that it doesn't create duplicate groups.
And how can I make the list smaller (The desired output) when printing the created lists.
If I wasn't clear enough or if I didn't explain what I want very well, let me know. I'll try to make it clearer.
Create an object similar to this. It takes 4 strings (2 pairs). Puts the strings into array and sorts this array. That means any combination of strings you put in will be converted into one sorted combination, but the object internaly remembers which person is person1, person2, ...
private class TwoPairs {
private final String person1;
private final String person2;
private final String person3;
private final String person4;
private final String[] persons;
TwoPairs(String person1, String person2, String person3, String person4) {
this.person1 = person1;
this.person2 = person2;
this.person3 = person3;
this.person4 = person4;
persons = new String[4];
persons[0] = person1;
persons[1] = person2;
persons[2] = person3;
persons[3] = person4;
// if we sort array of persons it will convert
// any input combination into single (sorted) combination
Arrays.sort(persons); // sort on 4 objects should be fast
// hashCode and equals will be comparing this sorted array
// and ignore the actual order of inputs
}
// compute hashcode from sorted array
#Override
public int hashCode() {
return Arrays.hashCode(persons);
}
// objects with equal persons arrays are considered equal
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
TwoPairs other = (TwoPairs) obj;
if (!Arrays.equals(persons, other.persons)) return false;
return true;
}
// add methods which you might need
// getters for individual persons
// String getPerson1() { return person1; }
// or perhaps pairs of persons
// String[] getPair1() { return new String[] {person1, person2}; }
// add sensible toString method if you need it
}
Your ArrayList x will change like this
ArrayList<TwoPairs> x = new ArrayList<TwoPairs>();
before adding new TwoPairs object into x check if this list already contains this object.
if (!x.contains(twoPairsObject)) {
x.add(twoPairsObject);
}
I have two ArrayLists.
List of dates
List of respective data.
Both are synchronized. I sometimes have more than one data on a same date. I need to create two lists: unique dates and the data (averaged) respectively. So far, I have tried the following methods
int i = 1;
for(int it =0; it < predatetime.size() - 1; it++){
//Compare each element with the next one
if(predatetime.get(it+1) == predatetime.get(it)){
i++;
weight = preweight.get(it+1) + weight;
//If equal, add weights and increment a divisor for averaging
}
else { //if not equal, add to the new lists
if(it == predatetime.size() - 2){ //if the last element is not equal to its previous one, just add it to the list
newDateTime.add(predatetime.get(it+1));
newWeight.add(preweight.get(it+1));
break;
}
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
weight = preweight.get(it+1); //re-initialize variables
i = 1;
}
if(it == predatetime.size() - 2){
weight = weight / i;
newDateTime.add(predatetime.get(it));
newWeight.add(weight);
}
}
There are a lot of problems with this code.
If the list has only one element, it fails. (I know I can write 2 more lines to care of this). Is there a better way to do this?
I know there are similar questions on this website, but still I'm unable to resolve the problem.
This is the full solution
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class CustomList {
public static void main(String[] args) {
ArrayList<String> date = new ArrayList<>();
date.add("1");
date.add("2");
date.add("2");
date.add("3");
System.out.println(date);
ArrayList<Integer> value = new ArrayList<>();
value.add(1);
value.add(2);
value.add(4);
value.add(3);
System.out.println(value);
new MyCls().createList(date, value);
}
}
class MyCls {
ArrayList uniqueDate = new ArrayList<String>();
ArrayList averageValue = new ArrayList<Integer>();
LinkedHashMap store = new LinkedHashMap<String, CountEntry>();
class CountEntry {
int value;
int count;
CountEntry() {
}
CountEntry(int v, int c) {
value = v;
count = c;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
public void createList(ArrayList<String> date, ArrayList<Integer> value) {
for (int i = 0; i < date.size(); i++) {
CountEntry tmp = (CountEntry) store.get(date.get(i));
if (tmp == null) {
store.put(date.get(i), new CountEntry(value.get(i), 1));
} else {
int tmpVal = tmp.getValue();
int tmpCount = tmp.getCount();
store.put(date.get(i), new CountEntry(value.get(i) + tmpVal, ++tmpCount));
}
}
ArrayList<String> uniqueDate = new ArrayList<String>(store.keySet());
ArrayList<CountEntry> tempAvgList = new ArrayList<CountEntry>(store.values());
for (CountEntry ce : tempAvgList) {
averageValue.add(ce.getValue() / ce.getCount());
}
System.out.println("Output");
System.out.println(uniqueDate);
System.out.println(averageValue);
}
}
/*
OUTPUT Snap:
[1, 2, 2, 3]
[1, 2, 4, 3]
Output
[1, 2, 3]
[1, 3, 3]
*/
If you try to make your list elements unique why you not try to convert the list to set collection
Set<Foo> foo = new HashSet<Foo>(myList);
Why not create a Map instead with the dates as the key and have the value as a list. This will allow you to keep the dates unique, at the same allow you to have your data as a list.
Map<String, ArrayList<myData>> myMap = new HashMap<String, ArrayList<myData>>();
Then you can just find if your key exists, if it does add it to the array list by using the key to identify the correct list. If it doesnt exist it, add it to the map
Thanks to #Rambler and #JulianGurung, I created a HashMap and it works
HashMap<Integer, Float> hm = new HashMap<Integer,Float>();
int occurance = 0;
float weight = 0;
hm.put(predatetime.get(0), 0f); //initialize with the first value
for(Map.Entry m : hm.entrySet()){
for( int it = 0; it < predatetime.size(); it++){
if(m.getKey() == predatetime.get(it)){
weight = (Float) m.getValue() + preweight.get(it); //Sum all the same data in order to avg later
hm.put(predatetime.get(it), weight);
occurance++;
}
else{ //if it is not equal, add the new element to the map
hm.put(predatetime.get(it), preweight.get(it));
}
}
weight = weight / occurance;
hm.put((Integer) m.getKey(), weight);
weight = 0;
occurance = 0;
}
I want to create a game and I need to read file from the notepad
when I use my loadfile.java alone, it work very well. Then, I would like to copy my data into datafile.java as it will be easier for me to do the fighting scene. However, I can't copy the array in my loadfile.java to the datafile.java and I don't understand why.
import javax.swing.*;
import java.io.*;
import java.util.Scanner;
public class loadfile
{
static String filename = "Save.txt";
static int size = 4;
static int s;
static int[] number;
static String[] line;
private static void load() throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(filename));
while (reader.readLine()!= null)
{
size++;
}
size -= 4;
reader.close();
line = new String[size];
number = new int[size];
BufferedReader reader2 = new BufferedReader(new FileReader(filename));
for (int i = 0; i < size; i++)
{
line[i] = reader2.readLine();
}
reader2.close();
for (int i = 4; i < size; i++)
{
number[i] = Integer.parseInt(line[i]);
}
}
public static String[] getData()
{
return line;
}
public static int[] getNumber()
{
s = size - 4;
int[] num = new int[s];
for (int i = 0; i < s; i++)
{
num[i] = number[i+4];
}
return num;
}
public static int getDataSize()
{
return size;
}
public static int getNumberSize()
{
return size - 4;
}
This is my loadfile.java
I use the file with 4 names and 9 * n int in the notepad as I want to check whether I have the character first before I read the file. However, before I can handle this problem, I got another problem that I can't copy the array into my datafile.java
The datafile.java is separate with two constructor. One is for Starting the game and one is for loading the data. The constructor with the (int num) is the problem I have. First, I would like to show the java first:
import java.util.Arrays;
import java.io.*;
public class datafile
{
private static String[] data;
private static int[] number;
private static String[] name;
private static int[] a, d, s;
private static int[] hp, maxhp;
private static int[] mp, maxmp;
private static int[] lv, exp;
public datafile()
{
initialization();
name[0] = "Pet";
a[0] = 100;
d[0] = 100;
s[0] = 100;
hp[0] = 500;
mp[0] = 500;
maxhp[0] = 500;
maxmp[0] = 500;
exp[0] = 100;
lv[0] = 1;
}
public datafile(int num) throws IOException
{
initialization();
loadfile l = new loadfile();
for (int i = 0; i < l.getNumberSize(); i++)
{
number[i] = l.getNumber()[i];
}
for (int i = 0; i < l.getDataSize(); i++)
{
data[i] = l.getData()[i];
}
for(int i = 0; i < 4; i++)
{
name[i] = data[i];
}
for(int i = 0; i < 4; i++)
{
a[i] = number[1+(i*9)];
d[i] = number[2+(i*9)];
s[i] = number[3+(i*9)];
hp[i] = number[4+(i*9)];
mp[i] = number[5+(i*9)];
maxhp[i] = number[6+(i*9)];
maxmp[i] = number[7+(i*9)];
lv[i] = number[8+(i*9)];
exp[i] = number[9+(i*9)];
}
}
public static String getName(int n)
{
return name[n];
}
public static int getAttack(int n)
{
return a[n];
}
public static int getDefense(int n)
{
return d[n];
}
public void initialization()
{
name = new String[3];
a = new int[3];
d = new int[3];
s = new int[3];
hp = new int[3];
mp = new int[3];
maxhp = new int[3];
maxmp = new int[3];
lv = new int[3];
exp = new int[3];
}
public static void main (String[] args) throws IOException
{
new datafile(1);
}
}
When I run the program, the debugging state this line
data[i] = l.getData()[i];
as an error
I don't know what wrong with this line and I tried so many different ways to change the way the copy the method. However, it didn't work
The error says this:
Exception in thread "main" java.lang.NullPointerException
at datafile.<init>(datafile.java:38)
at datafile.main(datafile.java:92)
I hope you guys can help me with this problem because I don't want to fail with my first work
in your datafile(int num)
you call
loadfile l = new loadfile();
but you never call the load() method on you loadfile
l.load();
Edit: my bad, I didn't see your initialization method, but regardless, I'm going to stick with my recommendation that you radically change your program design. Your code consists of a kludge -- you've got many strangely named static array variables as some kind of data repository, and this suggests that injecting a little object-oriented design could go a long way towards creating classes that are much easier to debug, maintain and enhance:
First I recommend that you get rid of all of the parallel arrays and instead create a class, or likely classes, to hold the fields that need to be bound together and create an ArrayList of items of this class.
For example
public class Creature {
private String name;
private int attack;
private int defense;
// constructors here
// getters and setters...
}
And elsewhere:
private List<Creature> creatureList = new ArrayList<>();
Note that the Creature class, the repository for some of your data, should not be calling or even have knowledge of the code that loads the data, but rather it should be the other way around. The class that loads data should create MyData objects that can then be placed within the myDataList ArrayList via its add(...) method.
As a side recommendation, to help us now and to help yourself in the future, please edit your code and change your variable names to conform with Java naming conventions: class names all start with an upper-case letter and method/variable names with a lower-case letter.
I have two ArrayLists, teamList1 and teamList2, which each contain five Team objects. I'm comparing those contents to each other in one of my methods. I must pass in these two ArrayLists as a single 2-element simple array argument, Objects[], into the method. I'm getting a compiler error because I'm struggling with casting from type Objects into type Team. In other words, changing from a Collection to a simple array back to a Collection is giving me an error. Anyone have a tip on my casting error?
CommonElements.java
package test;
import javax.swing.*;
import java.util.*;
public class CommonElements {
List<Comparable> teamList1 = new ArrayList<Comparable>();
List<Comparable> teamList2 = new ArrayList<Comparable>();
List<Comparable> commonList = new ArrayList<Comparable>();
Object[] listCollection = new Object[2];
int comparisonCount;
public static void main(String[] args) {
new CommonElements();
}
public CommonElements() {
comparisonCount = 0;
Team a = new Team("Boston");
Team b = new Team("Seattle");
Team c = new Team("Newark");
Team d = new Team("Houston");
Team e = new Team("Salt Lske City");
teamList1.add(a);
teamList1.add(b);
teamList1.add(c);
teamList1.add(d);
teamList1.add(e);
Team f = new Team("Seattle");
Team g = new Team("Nashville");
Team h = new Team("St. Louis");
Team i = new Team("New York");
Team j = new Team("Boston");
teamList2.add(f);
teamList2.add(g);
teamList2.add(h);
teamList2.add(i);
teamList2.add(j);
listCollection[0] = teamList1;
listCollection[1] = teamList2;
findCommonElements(listCollection);
System.out.println(comparisonCount);
}
public Comparable[] findCommonElements(Object[] collections)
{
ArrayList<Object> objectTeam1 = new ArrayList<Object>(Arrays.asList(collections[0]));
ArrayList<Object> objectTeam2 = new ArrayList<Object>(Arrays.asList(collections[1]));
ArrayList<Team> team1 = (ArrayList)objectTeam1;
ArrayList<Team> team2 = (ArrayList)objectTeam2;
Team[] commonList = new Team[5];
int i = 0;
for(Team x:team1)
{
for(Team y:team2)
{
comparisonCount++;
if(x.compareTo(y) == 0)
{
commonList[i] = x;
System.out.println(commonList[i].teamName);
i++;
break; /*to ensure it looks for only one match per entry*/
}
}
}
return commonList;
}
public int getComparisons()
{
return comparisonCount;
}
}
Team.java
package test;
public class Team implements Comparable<Team> {
String teamName = new String();
public void setName ( String n ) {
teamName = n;
}
public Team(String n) {
setName(n);
}
public int compareTo(Team x)
{
if(this.teamName.equals(x.teamName))
{
return 0;
}
else
{
return -1;
}
}
}
That is a very unfortunate and odd way of passing the arguments, but anyway, to make it work, you can do:
#SuppressWarnings("unchecked")
ArrayList<Team> team1 = (ArrayList<Team>)collections[0];
#SuppressWarnings("unchecked")
ArrayList<Team> team2 = (ArrayList<Team>)collections[1];
Your existing code was taking each ArrayList, putting it into a one element array, wrapping that array as a list, creating an ArrayList from it, and trying to view the ArrayList<ArrayList<Team>> as an ArrayList<Team>.
A few other things I see... you don't need to assign these to variables if you're only using them to add to the list:
Team a = new Team("Boston");
...
teamList1.add(a);
You can simply do:
teamList1.add(new Team("Boston"));
You don't need to create the listCollection array separately, because you can create it inline when passing the arguments:
findCommonElements(new Object[] { teamList1, teamList2 });
In your Team class, this:
String teamName = new String();
Should simply be:
String teamName;
In your compareTo method:
public int compareTo(Team x)
{
if(this.teamName.equals(x.teamName))
{
return 0;
}
else
{
return -1;
}
}
That should be:
public int compareTo(Team x)
{
return teamName.compareTo(x.teamName);
}
which is shorter, and honors the compareTo requirement that sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) for all x and y.
i have one arrayList
List value = new ArrayList();
this arraylist are value is = {a,b,c,d}
i have required combination to string using this arraylist
Required Output: abcd,bcd,acd,abd,abc,cd,bd,bc,ad,ac,ab,a,b,c,d,null
If it's possible? then please send me code....
It's my code but not perfectly work
import java.util.ArrayList;
import java.util.List;
public class PossibleCombination {
public static void main(String[] args) {
List segList = new ArrayList();
for(int i=65;i<70;i++){
segList.add((char)i);
}
int segSize = segList.size();
int[][] a = new int[segSize][2];
int i;
for(i=0; i<= segSize-1; i++)
{
a[i][0] = 0;
a[i][1] = 1;
}
boolean b1 = true;
int t =0;
while(b1)
{
StringBuffer stb = new StringBuffer();
for(i=0;i<segSize; i++)
{
if(a[i][0]==0)
stb.append(segList.get(i));
}
System.out.println(stb);
if(t>=a.length){
t=0;
}
int Pos=t;
while(a[Pos][0]>=a[Pos][1])
{
if(Pos<segSize-1)
Pos++;
else
break;
}
a[Pos][0]++;
Pos--;
while(Pos>=0)
{
if(a[Pos][0]>0)
{
a[Pos][0]--;
break;
}
Pos--;
}
t++;
if(a[segSize-1][0]> a[segSize-1][1]){
b1 = false;
}
}
}
}
Yes, It is definitely possible. However, it will of course require exponential time.
I will leave the actual implementation to you, but here are some hints.
The easiest way to do this is recursively, but that will take a lot of stack space very quickly.
Another way to do this is via some kind of breath-first expanding of the resulting list. This can be done iteratively with a FIFO queue.
List<String[]> value = new ArrayList<String[]>();
String[] item = {"a","b","c"};
value.add(item);