Java Version 8
IntelliJ IDEA 2016.1.4
Build #IC-145.2070, built on August 2, 2016
JRE: 1.8.0_77-b03 x86
JVM: Java HotSpot(TM) Server VM by Oracle Corporation
I need to be able to copy this ArrayList for when changes are made to values in the ArrayList (added, removed, edited)... And these changes made, must only be made in the copied ArrayList without Affecting the original ArrayList.
Example Code Provided Below:
Line 61: is where the copy of pass-by-value should happen.
Lines 19-23: is where I was thinking of creating the copy pass-by-value method, and then just using the method call on line#61.
package Main;
import java.util.ArrayList;
public class QuickTest {
private static void printHpMpLvlsValues(ArrayList<ArrayList<ArrayList<Integer>>> hpMpLvlsValues, int hpValuesIndex, int mpValuesIndex){
int currentLvl = 1;
for (int lvlIndex = 0; lvlIndex < hpMpLvlsValues.get(hpValuesIndex).size(); lvlIndex++, currentLvl++){
System.out.println("****************** LVL(" + currentLvl + ") Possible Values ******************");
System.out.println("HP Values = " + hpMpLvlsValues.get(hpValuesIndex).get(lvlIndex));
System.out.println("MP Values = " + hpMpLvlsValues.get(mpValuesIndex).get(lvlIndex));
System.out.println();
}
System.out.println("*************************************************************");
System.out.println("*************************************************************");
System.out.println("*************************************************************");
System.out.println();
}
private static ArrayList<ArrayList<ArrayList<Integer>>> getCopyThreeDimArrListPassByValue(ArrayList<ArrayList<ArrayList<Integer>>> origThreeDimArrList){
ArrayList<ArrayList<ArrayList<Integer>>> copiedThreeDimArrList = new ArrayList<>();
//ToDo: fill in code to copy the Three Dimensional ArrayList as pass-by-value.
return copiedThreeDimArrList;
}
public static void main(String[] args) {
int hpValuesIndex = 0;
int mpValuesIndex = 1;
// Setup originalHpMpLvlsValues ArrayList...
ArrayList<ArrayList<ArrayList<Integer>>> originalHpMpLvlsValues = new ArrayList<>();
ArrayList<ArrayList<ArrayList<Integer>>> copiedHpMpLvlsValues = new ArrayList<>();
ArrayList<ArrayList<Integer>> hpLvlsValues = new ArrayList<>();
ArrayList<ArrayList<Integer>> mpLvlsValues = new ArrayList<>();
int maxLvl = 10;
int lvlTotalNumOfValuesPerLvl = 5;
int currentHpValue = 50;
int IncreaseHpValue = 50;
int currentMpValue = 10;
int IncreaseMpValue = 10;
for (int lvlIndex = 0; lvlIndex < maxLvl; lvlIndex++){
hpLvlsValues.add(new ArrayList<>());
mpLvlsValues.add(new ArrayList<>());
for (int valueNum = 1; valueNum <= lvlTotalNumOfValuesPerLvl; valueNum++){
hpLvlsValues.get(lvlIndex).add(currentHpValue);
mpLvlsValues.get(lvlIndex).add(currentMpValue);
currentHpValue += IncreaseHpValue;
currentMpValue += IncreaseMpValue;
}
}
originalHpMpLvlsValues.add(hpLvlsValues);
originalHpMpLvlsValues.add(mpLvlsValues);
// End Setup originalHpMpLvlsValues ArrayList...
// Print multiple hp/mp possible level results to system output
System.out.println("************************************************************");
System.out.println("Original HP/MP Levels Results:");
printHpMpLvlsValues(originalHpMpLvlsValues, hpValuesIndex, mpValuesIndex);
// Attempt to copy originalHpMpLvlsValues ArrayList as pass-by-value
copiedHpMpLvlsValues = originalHpMpLvlsValues; // <--------- Insert how to copy pass-by-value here
// Change hpValue for 5th level from 1150 to 1175
// ... this change should only affect "copiedHpMpLvlsValues" ArrayList and NOT the "originalHpMpLvlsValues" ArrayList
int lvlFiveIndex = 4;
copiedHpMpLvlsValues.get(hpValuesIndex).get(lvlFiveIndex).set(2, 1175);
// Print change made to copiedHpMpLvlsValues ArrayList
System.out.println("************************************************************");
System.out.println("Copied HP/MP Levels Results with change(s):");
printHpMpLvlsValues(copiedHpMpLvlsValues, hpValuesIndex, mpValuesIndex);
// Print originalHpMpLvlsValues ArrayList to ensure NO changes were made to this ArrayList
System.out.println("************************************************************");
System.out.println("Original HP/MP Levels Results without change(s):");
printHpMpLvlsValues(originalHpMpLvlsValues, hpValuesIndex, mpValuesIndex);
}
}
As a side-note, I got help with how to copy two dimensional ArrayLists as pass-by-value here -> Copy Two Dimensional ArrayList as new (read sweepers answer at the bottom done with 1 line of code)
Filled in the copy method on lines 19-23 in original post...
private static ArrayList<ArrayList<ArrayList<Integer>>> getCopyThreeDimArrListPassByValue(ArrayList<ArrayList<ArrayList<Integer>>> origThreeDimArrList){
ArrayList<ArrayList<ArrayList<Integer>>> copiedThreeDimArrList = new ArrayList<>();
ArrayList<ArrayList<Integer>> copiedArr;
for (ArrayList<ArrayList<Integer>> origArr: origThreeDimArrList){
copiedArr = new ArrayList<>(origArr.stream().map(x -> new ArrayList<>(x)).collect(Collectors.toList()));
copiedThreeDimArrList.add(copiedArr);
}
return copiedThreeDimArrList;
}
Then I just use this method call on line#61(now 67)...
copiedHpMpLvlsValues = getCopyThreeDimArrListPassByValue(originalHpMpLvlsValues);
However... I was wondering if there was a better way to do this or a built-in library I could use for this??
Related
Lets say I have a public class called GameBoard that will be a two dimensional array with 4 rows and 5 columns. The spaces in the array are filed with String values from 1 to 20. A card will be drawn that has a name (King of Spades for example) . If the user inputs 15 I will store it in a String variable called userLocation. What would be the most efficient way to create a method that takes the input location and updates the array with the name of the Card? Would a for loop be most efficient?
public GameBoard() {
square = new String[4][5];
square[0][0] = new String("1");
square[0][1] = new String("2");
square[0][2] = new String("3");
square[0][3] = new String("4");
square[0][4] = new String("5");
square[1][0] = new String("6");
square[1][1] = new String("7");
square[1][2] = new String("8");
square[1][3] = new String("9");
square[1][4] = new String("10");
square[2][1] = new String("11");
square[2][2] = new String("12");
square[2][3] = new String("13");
square[3][1] = new String("14");
square[3][2] = new String("15");
square[3][3] = new String("16");
square[2][0] = new String(17);
square[3][0] = new String(18);
square[2][4] = new String(19);
square[3][4] = new String(20);
}
My preferred method as of now would look something like this but it gives me the error code "type mismatch:cannot convert string to boolean" under userLocation = board[i][j]
public String[][] updateBoard(String userLocation, Card card, String[][] board) {
for (int i = 0; i <4; i++)
{
for (int j = 0; j < 5; j++)
{
if(userLocation = board[i][j]) {
board[i][j] = card.name;
}
}
}
return board;
}
So the reason it will not compile is your = does not return a boolean expression. == would, but it's still not what you want, since you want to check if the String contents are the same, not if they're the same object, so use .equals.
But, no, I think you don't want to depend on strings to identify locations. What if you want to replace a card? And why look through everything when you need not?
Rather if i is some number between 1 and 20, identify the corresponding spot in the array by square[(i-1)/5][(i-1)%5]
That should bypass the issue you are having with matching strings.
So for example, your constructor becomes:
public GameBoard() {
square = new String[4][5];
for (int i=1; i<=20;i++){
square[(i-1)/5][(i-1)%5]=""+i;//initialize with 1 to 20 if you like
}
and userLocation is an int.
Hoping for some help - I've been asked to write a hotel room system using methods for uni. All has been going well until I try to order the array alphabetically.
I have managed to get it to order within the method but it updated the main array (hotel). I want it to keep it within the order method, if that makes sense?
I've included a cut down version below without all the functions.
Currently it will reorder the array hotel so if you view the rooms the array will print like 'e,e,e,etc, George, Peter, Robert' instead of keeping its original form 'e, Robert, Peter, e,e,etc, George'
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String roomName;
int roomNum = 0;
String[] hotelRef = new String[12];
String[] hotel = new String[12];
initialise(hotel); //initialise
while (roomNum < 13) {
System.out.println("Please select from the menu:");
System.out.println("V : View rooms");
System.out.println("O : Order Guests alphabetically");
String selection = input.next();
switch (selection) {
//There are more switch cases on the original version
case "O":
order(hotel);
break;
default:
System.out.println("");
}
}
}
private static void order(String[] hotelRef) {
int j;
boolean flag = true; //will determine when the sort is finished
String temp;
String[] order = new String[12];
order = hotelRef;
while (flag) {
flag = false;
for (j = 0; j < order.length - 1; j++) {
if (order[j].compareToIgnoreCase(order[j + 1]) > 0) {
//ascending sort
temp = order[j];
order[j] = order[j + 1]; // swapping
order[j + 1] = temp;
flag = true;
}
}
}
for (int y = 0; y < order.length; y++) {
if (!order[y].equals("e")) {
System.out.println("Room " + y + " is occupied by " + order[y]);
}
}
System.out.println("Ordering completed");
}
You should clone the hotelRef instead of assigning the reference like this order = hotelRef;
You could do the following while creating the order array :
String[] order = new String[hotelRef.length]; // to make sure that order has the right size.
and instead of order = hotelRef;
for (int i=0;i<order.length;i++)
order[i]=hotelRef[i]; // thereby cloning
or use System.arraycopy() or any other method to accomplish cloning the array.
You can make copy of hotel array in your order method:
String[] hotelCopy = new String[hotelRef.length];
System.arraycopy(hotelRef, 0, hotelCopy, 0, hotelRef.length);
And then just use hotelCopy inside your order method.
The problem lies with the following line
order = hotelRef;
Change it to
order = hotelRef.clone();
Though you are creating a new object, you have assigned the reference to outer object only. So whatever changes you make in the inner object it will be reflected to the outer object.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I want to read a file which has the following information:
4 //no. of machines
1,3,6,1 //timings for machine 1
1,3,6,1 //timings for machine 2
1,3,6,1 //timings for machine 3
1,3,6,1 //timings for machine 4
2,4,8,10 //cost for machine 1
2,4,8,10 //cost for machine 2
2,4,8,10 //cost for machine 3
2,4,8,10 //cost for machine 4
The no. of timing arrays and cost arrays depends on the no. of machines. An element in index 'i' of timing array is associated with the same index in cost array. For example, timing 1 for machine 1 incurs cost of 2, and timing 3 costs 4. Can anyone please suggest what data structure would be perfect for this scenario and how should I proceed with it?
Thanks in advance.
You can use a Map to define the relationship between timing and cost. Alternatively you can have a class TimeCost for time cost relationship.
public class TimeCost{
private Integer time;
private Integer cost;
}
public class Machine{
// private Map<Integer,Integer> timeCost; //possible alternative
private List<TimeCost> timeCost;
}
First, you should probably use a Pair to conserve the relationship between a timing and a cost:
class Pair {
int timing;
int cost;
}
Then, I'm assuming you don't receive information about how many pieces of timing/cost you get, so you'll have to use an ArrayList to represent a machine's information:
class Machine {
ArrayList<Pair> timingAndCost;
}
Then, since the number of machines is specified for you, use a fixed-size array to store the machines:
Machine[] machines = new Machine[numberOfMachines];
If you're considering just storing the ArrayLists in an array, like this:
ArrayList<Pair>[] machines = new ArrayList<Pair>[numberOfMachines];
It doesn't work, because Java doesn't allow you to declare a generic array. But if you really don't like to have the Machine class, then you can just use an ArrayList to store the ArrayList<Pair>:
ArrayList<ArrayList<Pair>> machines = new ArrayList<>(numberOfMachines);
import java.util.ArrayList;
class DaMachine {
private final int mMachineIndex;
private final int[] mTimings;
private final int[] mCosts;
public DaMachine(final int pMachineIndex, final int[] pTimings, final int[] pCosts) {
mMachineIndex = pMachineIndex;
mTimings = pTimings;
mCosts = pCosts;
}
#Override public String toString() {
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < mTimings.length; i++) {
sb.append(mTimings[i] + ":" + mCosts[i] + " ");
}
return "Machine [#" + mMachineIndex + ": " + sb + "]";
}
}
class CrazyFile {
static public String CRAZY = "4 //no. of machines \r\n" + //
"1,3,6,1 //timings for machine 1\r\n" + //
"1,3,6,1 //timings for machine 2\r\n" + //
"1,3,6,1 //timings for machine 3\r\n" + //
"1,3,6,11 //timings for machine 4\r\n" + //
"2,4,8,10 //cost for machine 1\r\n" + //
"2,4,8,10 //cost for machine 2\r\n" + //
"2,4,8,10 //cost for machine 3\r\n" + //
"2,4,8,111 //cost for machine 4";
}
public class ReadCrazyFile {
public static void main(final String[] args) {
final String[] lines = CrazyFile.CRAZY.replace("\r\n", "\n").replace("\r", "\n").split("\n");
final int numberOfMachines = Integer.parseInt(cleanString(lines[0]));
final ArrayList<String> timingStrings = new ArrayList<>(numberOfMachines);
final ArrayList<String> costStrings = new ArrayList<>(numberOfMachines);
int offset = 1;
// add timings
for (int relIndex = 0; relIndex < numberOfMachines; relIndex++) {
timingStrings.add(cleanString(lines[offset + relIndex]));
}
offset += numberOfMachines;
// add costs
for (int relIndex = 0; relIndex < numberOfMachines; relIndex++) {
costStrings.add(cleanString(lines[offset + relIndex]));
}
offset += numberOfMachines; // not necessary unless used later
// convert into objects
final ArrayList<DaMachine> machines = new ArrayList<>(numberOfMachines);
for (int machineIndex = 0; machineIndex < timingStrings.size(); machineIndex++) {
final String timingString = timingStrings.get(machineIndex);
final String costsString = costStrings.get(machineIndex);
final int[] timings = convertToIntArr(timingString);
final int[] costs = convertToIntArr(costsString);
final DaMachine terminator = new DaMachine(machineIndex, timings, costs);
machines.add(terminator);
}
for (final DaMachine m : machines) {
System.out.println("" + m);
}
}
static private String cleanString(final String pString) {
return pString.split("//")[0].trim();
}
static private int[] convertToIntArr(final String pTimingString) {
final String[] words = pTimingString.split(",");
final int[] ret = new int[words.length];
for (int i = 0; i < words.length; i++) {
ret[i] = Integer.parseInt(words[i].trim());
}
return ret;
}
}
This is the structure that you need to resolve the issue.
ArrayList<ArrayList<Integer>> listOLists = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list1= new ArrayList<Integer>();
list1.add(4);
listOLists.add(list1)
ArrayList<Integer> list2= new ArrayList<Integer>();
list2.add(1);
list2.add(3);
list2.add(6);
list2.add(1);
listOLists.add(list2);
ArrayList<Integer> list3= new ArrayList<Integer>();
list3.add(1);
list3.add(3);
list3.add(6);
list3.add(1);
listOLists.add(list3);
Like this wise you can proceed. Its just a rough idea please optimize this code according to your need.
I have an array of arrays with color variable
Color [] [] bin = new Color [64] [];
afterwards I want to insert colors into this array
Im looping through a list of colors and tmpColor is the particular color in the loop. I need to insert it into the specific loop it belongs.
int idx = 16* (tmpColor.getRed()/64) + 4*(tmpColor.getGreen()/64) + (tmpColor.getBlue()/64);
bin[idx].push(tmpColor);
However this doesn't seem to work. How do I add a color into the array in the specific index?
How I solve it is the following: instead of creating an array of arrays I created and array of ArrayLists
int size = 64;
ArrayList<Color>[] lists = new ArrayList[size];
for( int i = 0; i < size; i++) {
lists[i] = new ArrayList<Color>();
}
After that I pushed the elements to their particular bin ( in this case in lists)
lists[idx].add(tmpColor);
Afterwards getting the lenght and the first color in the array is s follows:
for (ArrayList<Color> p : lists){
System.out.println("size of bin" + p.size());
if (p.isEmpty())
continue;
else {
System.out.println("list" + p.get(0));
}
}
If you need a List of colors for your index you can use a Map:
private Map<Integer, List<Color>> bin = new HashMap<Integer, List<Color>>();
int idx = 16* (tmpColor.getRed()/64) + 4*(tmpColor.getGreen()/64) + (tmpColor.getBlue()/64);
if(bin.get(idx)==null) bin.put(idx, new ArrayList<Color>());
bin.get(idx).add(tmpColor); //This should be exactly what you need
You can use also different structures like List<List<Color>> or List<Color>[]. Every structure relays on a List since List can be updated and created without knowing the initial length.
What I would do is create a separate class for color bin and some useful methods within:
public class Bin{
private List<Color> colors = new ArrayList<Color>();
public void addColor(Color col){
this.colors.add(col);
}
public List<Color> getColors(){
return this.colors;
}
public boolean hasColor(Color col){
return colors.contains(col);
}
//and so on...
}
And the best structure for your goal now is a map with lazy initialization:
private Map<Integer, Bin> myBinsOfColors = new HashMap<Integer, Bin>();
int idx = 16* (tmpColor.getRed()/64) + 4*(tmpColor.getGreen()/64) + (tmpColor.getBlue()/64);
if(myBinsOfColors.get(idx)==null) myBinsOfColors.put(idx, new Bin()); //Lazy
myBinsOfColors.get(idx).addColor(tmpColor); //This should be exactly what you need
To get the avarage and the number of colors you can implement two methods in the Bin class:
public class Bin{
private List<Color> colors = new ArrayList<Color>();
//As above.
public Color calculateAverage() {
Integer red = 0;
Integer blue = 0;
Integer green = 0;
if(!colors.isEmpty()) {
for (Color col : colors) {
red+= col.getRed();
green+= col.getGreen();
blue+= col.getBlue();
}
return new Color(red/colors.size(), green/colors.size(), blue/colors.size());
}
return null;
}
public int getColorCount(){
return this.colors.size();
}
//and so on...
}
I'm a noob in java and I can't seem to figure out how every time I add a new item to my ArrayList the previous ones become all the same as the new one. I did everything I learned from the posts here with the same issue but i still can't seem to figure out what's really wrong. I've been in this for a week now. Hopefully, someone would help.
Here's my code:
private void generation(String numberOfCase,int i, int j){
switch(numberOfCase){
case "N":
int tempN = 0;
if(i == 1)
tempN = 0;
if(i == 2)
tempN = 1;
forGenerating[i][j] = current[tempN][j];
forGenerating[tempN][j] = 0;
State tempNo = new State(forGenerating,current,1,howFar);
adding(tempNo);
//adding(forGenerating,current,1,howFar);
forGenerating[tempN][j] = forGenerating[i][j];
forGenerating[i][j] = 0;
break;
case "E":
int tempE = j+1;
forGenerating[i][j] = current[i][tempE];
forGenerating[i][tempE] = 0;
State tempEa = new State(forGenerating,current,1,howFar);
adding(tempEa);
//adding(forGenerating,current,1,howFar);
forGenerating[i][tempE] = forGenerating[i][j];
forGenerating[i][j] = 0;
break;
case "S":
int tempS = 0;
if(i == 0)
tempS = 1;
if(i == 1)
tempS = 2;
forGenerating[i][j] = current[tempS][j];
forGenerating[tempS][j] = 0;
State tempSo = new State(forGenerating,current,1,howFar);
adding(tempSo);
//adding(forGenerating,current,1,howFar);
forGenerating[tempS][j] = forGenerating[i][j];
forGenerating[i][j] = 0;
break;
case "W":
int tempW = j-1;
forGenerating[i][j] = current[i][tempW];
forGenerating[i][tempW] = 0;
State tempWe = new State(forGenerating,current,1,howFar);
adding(tempWe);
//adding(forGenerating,current,1,howFar);
forGenerating[i][tempW] = forGenerating[i][j];
forGenerating[i][j] = 0;
break;
}
}
private void adding(State temp){
State t = new State(temp);
if(closedList.equals(temp) == false){
forChecking.add(t);
iterator+=1;
}
}
I created an ArrayList of the class I've created for the states.
EDIT. Here's the class State. There are two constructors because I've been editing this code for a week now and doing all possible solutions I've read from the web.
import java.util.Arrays;
import java.util.Random;
public class State {
int[][] arr = new int[3][3];
int[][] parent = new int[3][3];
int g=0,f=0,h=0;
public State(int[][] arr, int[][] parent, int g, int h){
this.arr = Arrays.copyOf(arr, arr.length);
this.parent = Arrays.copyOf(parent, parent.length);
this.g = g;
this.h = h;
solveF();
}
public State(State temp){
this.arr = Arrays.copyOf(temp.arr, temp.arr.length);
this.parent = Arrays.copyOf(temp.parent, temp.parent.length);
this.g = temp.g;
this.h = temp.h;
solveF();
}
private void solveF(){
f = g+h;
}
}
Note that in Java, there is an actual object called ArrayList. Using that might simplify what you are trying to do, or at least making it easier to read as the methods of that class will have your code read like verbs.
The values are the same because you are storing the same array in the new State object. Consider one of the copy methods in the Array utilities. Later in your code you overwrite the value again, but since it's the same array object that was stored, they all look the same.
As to your code, it would be helpful to hear more of what you're trying to do. And maybe see some more surrounding code. However, some things that catch my eye:
The input variable numberOfCase is a string, which is confusing because one might think that should be a number.
While it is possible to switch on a string, consider making those inputs Enums.
In the adding() method, the code closedList.equals(temp) is comparing the objects. "closedList" sounds like a list or array, while "temp" is a State, so they will never be equal. Perhaps you meant to use !closedList.contains(temp)? (though be aware you'll need to Override .equals(Object o) in the State class)
It looks like your code is assuming a 2x2 matrix of values, and that i or j will always be 1 or 2, corresponding to the N,S,E,W string. For that type of case, I would suggest creating your own class with straight forward method names. Perhaps something like:
public class CompassGenerator{
//private fields
//returns previous Compass object, if required...
public Compass generateNorth(int howFar){...}
//Alternatively, pass in Compass object from which to generate
public Compass generateSouth(Compass prev, int howFar){...}
//etc...
}