print on the screen a repeat loop - java

I have a repeating structure in my Java class and wanted to present the data as follows:
Peter Black
John Red
I do not know if the structure is right, because if I leave to show the color only, the data is overwritten
public class Test {
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
String[] names= {"Peter", "John"};
String[] colors= {"Black", "Red"};
for (String name: names) {
Person d = new Person();
d.setName(name);
for (String color: colors) {
d.setColor(color);
}
persons.add(d);
}
for (Person a : persons) {
System.out.println(a.getName() + "-" + a.getColor());
}
}
}
Console:
Peter-Red
John-Red

Instead of using a nested for loop, which is not what you are trying to accomplish, loop through both arrays at the same time.
if (names.length != colors.length) {
// error! not a 1:1 relationship
return;
}
for (int i = 0; i < names.length && i < colors.length; i++) {
String name = names[i], color = colors[i];
Person d = new Person();
d.setName(name);
d.setColor(color);
persons.add(d);
}
I could just do i < names.length, however that will break if both arrays are different sizes, so i < names.length && i < colors.length will make sure i never exceeds either of the two arrays' lengths.
Edit:
I think the real problem here is how you are storing your info. Why are you using two string arrays, instead of a collection containing Person objects?

Stop looping on colors array inside your names loop. A traditional index based loop should help you get the same name and color from each array:
public class Test {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
List<Person> persons = new ArrayList<>();
String[] names= {"Peter", "John"};
String[] colors= {"Black", "Red"};
for (int i=0; i<names.length; i++) {
Person d = new Person();
d.setName(names[i]);
d.setColor(colors[i]);
persons.add(d);
}
for (Person a : persons) {
System.out.println(a.getName() + "-" + a.getColor());
}
}
}

You can use the Enum like
enum Entity {
Peter("Black"),
John("Red");
private final String color;
Entity(String color) {
this.color = color;
}

Notice that your color loop is INSIDE your name loop. So for each name you are setting it's color to the first color then the second color and then you are moving on to the next name.
Your biggest problem is probably the use of the advanced for loop, it doesn't give you an index. If you start with:
for(int i=0;i<names.length;i++)
the solution will probably be obvious (and simplify your code)
(I'd give more but it looks like something you are trying to learn with so I'll try to avoid spoilers)
Re your comment--if you wish to simply create only completely filled out objects, use
for(int i=0;i<Math.min(names.length, colors.length);i++)
If you wish to create partial objects, use Math.max and handle the case inside where either array's length is less than i. It's all business logic code... define what you want to do and do it.
How to handle bad data (Not part of the original problem):
If you want to handle the cases where the arrays are unequal, if you use the "Math.max" solution above, then adding the inside of the loop could look like this:
if(names.length < i)
d.setName(names[i])
if(colors.length < i)
d.setColor(colors[i])
This way there is no exception and you are safely setting values.
But since that leaves your objects invalid, you might be better off not allowing a different number of colors and names from your user. If he enters 3 names, then throw away blank colors and keep re-prompting until you have 3 colors--then stop prompting. It's always safest to catch problems like this as soon as possible.
Another good solution, start with:
if(names.length != colors.length)
throw new IllegalArgumentException("createUsers method must have the same number of names as colors but was called with "+names.length+" names and "+colors.length+" colors")
Ensuring your parameters are correct and throwing an exception if they are not simplifies your code a LOT and is generally a very good practice.

Related

How to count the nested list elements size using Java 7?

I have a Object which contains a list of another object which contains a list of another object and so on... suppose I want to get count of nested list elements(lets say last one), what should be best approach rather than using traditional for loop in java as I have done in below example -
public static void main(String[] args) {
Statement statement = new Statement();
statement.getInvAccount().add(new InvestmentAccount());
statement.getInvAccount().get(0).getSecAccountStmt().add(new SecurityStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
statement.getInvAccount().get(0).getSecAccountStmt().get(0).getTransactionStatement().add(new TransactionStatement());
// method to count the number of TransactionStatement
System.out.println("Size of TransactionStatement is : " + count(statement));
}
private static int count(Statement stmt) {
int countOfTransStmt = 0;
for (InvestmentAccount invAcc : stmt.getInvAccount()) {
if (invAcc != null) {
for (SecurityStatement secStmt : invAcc.getSecAccountStmt()) {
if (secStmt != null) {
countOfTransStmt = countOfTransStmt + secStmt.getTransactionStatement().size();
}
}
}
}
return countOfTransStmt;
}
In Java 7 you're not going to do better than two for loops. I wouldn't bother with anything different.
In Java 8 you can use streams to flatten it out:
private static int count(Statement stmt) {
return stmt.getInvAccount().stream()
.filter(Objects::nonNull)
.flatMap(InvestmentAccount::getSecAccountStmt)
.filter(Objects::nonNull)
.flatMap(SecurityStatement::getTransactionStatement)
.count();
}
I would encourage you to get rid of the null checks. If you're going to ignore nulls, better to just expect them not to be inserted in the first place. It'll get rid of a lot of extra if checks throughout your code, I expect.
I'd also encourage you not to abbreviate your variables and methods. Spell out "statement" and "investment" and the like. The abbreviations are harder to read and the brevity isn't really a win.
Similarly, try to use more descriptive method names. countTransactions is better for the main method. And for the various getters, methods that return lists ought to be plural: "getAccounts" rather than "getAccount". Notice how the getters now match the class names; if you know the class name, you know the getter name. You don't have to guess if one or the other is abbreviated:
private static int countTransactions(Statement statement) {
return statement.getInvestmentAccounts().stream()
.flatMap(InvestmentAccount::getSecurityStatements)
.flatMap(SecurityStatement::getTransactionStatements)
.count();
}
Recursion could work in this case:
General idea below:
private int countTransactions(object t)
{
int sum = 0;
if (t == null) return 0;
for (int i = 0; i < t.getAllSub().count; i++)
{
sum += countTransactions(t.subAt(i));
}
return sum;
}

Add card to hand in blackjack

How do I add a card to my hand when it says "addCardToHand" I tried card++; and hand++; neither worked. Is there a problem with my code, or did I just left something out? I feel like I need to add something but, I don't know what.
private AbstractCard[] hand;
private int winCount;
public AbstractPlayer() {
hand = new AbstractCard[0];
}
public AbstractPlayer(int score) {
}
public void addCardToHand( AbstractCard card ) {
AbstractCard[] NewHand = new AbstractCard[hand.length+1];
for ( int i = 0; i < NewHand.length; i++) {
NewHand[i] = hand[i];
}
}
public void resetHand() {
hand = new AbstractCard[0];
}
I think it's probably because hand[] has nothing in it. It gets created as an array with size 0, (no elements), and then when you add a card, you pull from the hand[] at index 0, but since the hand[] has no elements, it's not pulling from anywhere.
Basically, nowhere in your code does hand[] ever get to be an array with any elements in it, so when you take from hand[0] there's nothing there, because in hand = new AbstractCard[0];, [0] is the size of the array.
EDIT:
You might want to look into using an ArrayList (Oracle documentation) (Stack Overflow post), because they don't have a pre-defined size. In your case, you're adding elements as you go, so an ArrayList be very helpful. With an ArrayList, you won't have to constantly create new arrays.
You probably want to keep track of the next insert position for cards with some state like private int insertCursor = 0;
Your addCardToHand(AbstractCard) method can then simply be
public void addCardToHand(AbstractCard card) {
hand[insertCursor++] = card;
}

How to use a for loop to set String variable mixed with numbers to ""?

I have inherited a Java program which I need to change. In one part of the code, I see I have created over 1000 String variables such as:
String field01
String field02
...
String field1000
I want to make a for loop to set all of the mentioned variables to "", but I am having issues with building a correct format for the for loop.
How do I create field+(i) in the for loop to set field01 to "" and the rest?
A for loop... Well, you could make this an array, but there's not really any way to make this into a for loop without an array.
Here's an example with one:
String[] test = new String[1000];
for (int number; numer < 1000; number++){
test[number] = "";
}
You have to use Reflection for doing the same.
class Test {
String field1
String field2
...
String field1000
}
public class FieldTest {
public static void main(String args[]) {
Test t = new Test();
Class cls = t.getClass();
for(int i=0 ; i<=1000; i++){
Field f1 = cls.getField("field"+i);
f1.set(t, "");
}
}
}
You can't really do this in Java. An alternative is to make a String array where the index of the array is the number of the variable that you want. So field01 would be stored in your string array at index 1.
First, create an array. Second, use Arrays.fill:
String[] fields = new String[1000];
Arrays.fill(fields, "");
Later you can access or modify individual variables by indices like fields[index].
Creating 1000 variables with similar names is not how people program in Java.
I know it is not the exact answer, but may help you.or you will need to use reflection.
Map<String, String> container = new HashMap<String, String>();
for (int i = 0; i <1000; i++) {
container.put("field"+ i, "\"\" ");
}

Comparing With an ArrayList

My program calls for being able to delete a name and number from a phone book. I have gotten the deleting to work but it only deletes the index from the ArrayList that the text box corresponds to. I need to be able to delete both the name and the number from their respective arraylists by entering it into either texbox. Sorry if there is another answer to this i guess i dont really know how to word it correctly. My code is below.
ArrayList<String> Names = new ArrayList<String>();
ArrayList<String> Numbers = new ArrayList<String>();
if(e.getSource() == DeleteBtn)
{
if (NameTxt.getText() != null)
{
for( int i=0; i<= NamesList.size(); i++)
{
if(NamesList.contains(NameTxt.getText()))
{
NamesList.remove(i);
System.out.println(NamesList.size());
}
}
}
if (PhoneTxt.getText() != null)
{
for( int i=0; i<= NumbersList.size(); i++)
{
if(NumbersList.contains(PhoneTxt.getText()))
{
NumbersList.remove(i);
System.out.println(NumbersList.size());
}
}
}
}
If you HAVE to use ArrayLists then you might consider using an ArrayList of pairs.
You can create your own class, say PhoneBookEntry.
class PhoneBookEntry {
String _name;
String _phone;
// etc...
}
ArrayList<PhoneBookEntry>
Consider using a HashMap instead of the ArrayLists.
HashMap<String, String> numbersAndNames = new HashMap<String, String>();
numbersAndNames.put("John", "123 456 789");
If I were you, I would reconsider my logic. I'm going to try and avoid posting code for you to keep from giving you the answer/doing the work for you but...
I only see you modifying the NamesList variable. You aren't modifying the Names or Numbers ArrayList variables.
I would put your 'contains if statement' some place else. Your checking to see if NameList contains NameText a bunch of times. I don't see why you would need to check it more than once.
If you want to get smart, you can do away with the array completely and just use the getIndex() method to some effect in java...which gets the index corresponding to NameText (I'm being vague here deliberately, so think about what I'm saying).
You can use a HashMap if you want, but it's not necessary.
Per suggestion of using an additional class to track the name/number combo.
ArrayList contacts = new ArrayList();
if(e.getSource() == DeleteBtn) {
if (NameTxt.getText() != null) {
for( int i=0; i<= contacts.size(); i++) {
if(contacts.getName().contains(NameTxt.getText())) {
contacts.remove(i);
System.out.println(contacts.size());
}
}
}
public class PhoneContact {
private String name;
private String number;
/*
Getters and Setters
*/
}
First of all, NumbersList.contains(PhoneTxt.getText()) returns if PhoneTxt.getText() is anywhere in the list.
What you want to check is the NumbersList.get(i).equals(PhoneTxt.getText()) note that i used equals() instead of == operator
my friend actually found the answer, he simply added the other ArrayList(i), thank you to all who posted answers, as they gave me food for thought, just thought the logic of the answer would not work but i was proven wrong, here is the code for anyone interested.
if(e.getSource() == DeleteBtn)
{
if (NameTxt.getText() != null)
{
for( int i=0; i<= NamesList.size(); i++)
{
if(NamesList.contains(NameTxt.getText()))
{
NamesList.remove(i);
NamesList.remove(i);
System.out.println(NamesList.size());
System.out.println(NumbersList.size());
}
}
}
if (PhoneTxt.getText() != null)
{
for( int i=0; i<= NumbersList.size(); i++)
{
if(NumbersList.contains(PhoneTxt.getText()))
{
NumbersList.remove(i);
NamesList.remove(i);
System.out.println(NamesList.size());
System.out.println(NumbersList.size());
}
}
}
}

Is this proper use of storing values into an array via getText()?

In my Java program's constructor I have the following:
thirdRow.add(button);
button.setActionCommand("Sumbit");
button.addActionListener(this);
And here is the corresponding actionPerformed method that's supposed to take 3 values from some textfields and store them into arrays:
public void actionPerformed(ActionEvent e)
{
String arg = e.getActionCommand();
if (arg == "Submit")
{
//enlarge arrays
qtyStr = enlargeArray(qtyStr);
typeStr = enlargeArray(typeStr);
colorStr = enlargeArray(colorStr);
//add from textfields into current
qtyStr[qtyStr.length-1] = qty.getText();
typeStr[typeStr.length-1] = type.getText();
colorStr[colorStr.length-1] = color.getText();
}
}
//method to enlarge an array by 1
public String[] enlargeArray(String[] currentArray)
{
String[] newArray = new String[currentArray.length + 1];
for (int i = 0; i<currentArray.length; i++)
newArray[i] = currentArray[i];
return newArray;
}
When I run the application, populate the textfields, and click the submit button nothing happens. How can I verify that my string arrays are being appended like they're supposed to?
You've a problem here: if (arg == "Submit")
Don't compare Strings using ==. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two objects are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
Also, for safety's sake, I try to use String constants wherever possible so as not to be tripped up by misspellings.
If you want to do your code this way, I would probably do two things:
1) maintain index fields for each array for the next free index, and
2) I wouldn't recommend resizing your array by 1 each time, as our current code is running through the array 2 n times (n = array length), 1st to initialize the array, and 2nd to create a new array.
Two options to optimize thisL one would be be to look into the Arrays class. it contains methods such as Array.copyOf() that can perhaps be useful here. You could also check if the array is full, and if it is then resize it by a number greater than one to reduce extra work.
For instance:
import java.util.Arrays;
class Test{
private String[] a;
private int next;
public Test(int size){
a = new String[size];
next = 0;
}
public void add(String s){
if(next == a.length){
Arrays.copyOf(a, a.length+1);
}
a[next] = s;
next++;
}
}
The easiest way would be to use an ArrayList (or any class that implements the java.util.List interface), as previously mentioned by Jon Skeet - it will do all the work for you.

Categories

Resources