I have a list of objects "SaleItem". they are all objects of the same class. each object has a String field "name" and an int field "value". I want to see if one of the objects contains a name. It seems that I can't use the "contains" method to do this. I see two solutions. one is to iterate through all the objects to check if one has said name:
for (SaleItem item: myList) {
if (item.getName() == "banana") {
// do stuff
}
}
The other solution would be to create a new list of Strings from "myList" and use the contains method on that:
ArrayList<String> nameList = new ArrayList<>();
for (SaleItem item: myList) {
nameList.add(item.getName());
}
if (nameList.contains("banana")) {
// do stuff
}
I imagine the first method would be most efficient if I'm only doing it once, and the second would be more efficient if I'm doing it many times. Being a bit of a newbie without a formal education, I don't know what's proper in this situation.
Since SaleItem.getName() returns a string, you should be able to use "contains" method.
It seems like you have initialized the ArrayList or the SaleItem object incorrectly.
public class TestApp {
public static void main(String[] args) {
List<SaleItem> list = new ArrayList<SaleItem>();
SaleItem s1 = new SaleItem();
s1.setName("banana");
s1.setValue(1);
SaleItem s2 = new SaleItem();
s2.setName("apple");
s2.setValue(2);
list.add(s1);
list.add(s2);
for (SaleItem item: list) {
if (item.getName().contains("banana")) {
System.out.println("Pass");
}
}
}
}
class SaleItem {
private String name;
private int value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
Try with this code
public class SaleItem {
private String itemName;
public String getItemName() {
return itemName;
}
public SaleItem setItemName(String itemName) {
this.itemName = itemName;
return this;
}
#Override
public String toString() {
return "[SaleItem : { itemName = " + this.getItemName() + " }]";
}
public static void main(String[] args) {
ArrayList<SaleItem> nameList = new ArrayList<>();
nameList.add(new SaleItem().setItemName("banana"));
nameList.add(new SaleItem().setItemName("grape"));
nameList.add(new SaleItem().setItemName("watermelon"));
nameList.add(new SaleItem().setItemName("orange"));
nameList.add(new SaleItem().setItemName("guava"));
for (SaleItem item : nameList) {
if (item.toString().contains("banana")) {
// Do this
}
}
}
}
A List's .contains method isn't magical, it will generally just loop through the elements checking for equality, O(n) linear performance.
Your first solution is probably fine.
If you really did expect repeated access and wanted better than linear performance on subsequent lookups, you'd probably want to construct a Map<String,SaleItem>, or a Set<String> depending on what you wanted to do with it. But those solutions would normally only work on exact matches. Once you need case-insensitive matches, they have to be TreeMap or TreeSet with a case-insensitive comparator. And if you want partial matching (like using String.contains() or a regular expression), you'd want to go back to a linear search.
But don't do any of that unless you have to. Keep it simple.
Related
We have to create a object of any class to use their funtionalities unless those are static functionalities. But why we dont need to create a ArrayList object to use its methods like add, contains etc..
ArrayList<Egg> myList = new ArrayList<Egg>();
myList.add(a);
According to my understanding, myList is just variable which holds ArrayList object's reference of type ArrayList class. So again how can we write following without passing object to myList.
ArrayList<Egg> myList;
myList.add(a);
Complete code:
import java.util.ArrayList;
public class DotCom {
private ArrayList<String> locationCells;
public void setLocationCells(ArrayList<String> loc)
{
locationCells = loc;
}
public String checkYourself(String userInput)
{
String result = "miss";
int index = locationCells.indexOf(userInput);
if (index >= 0) {
locationCells.remove(index);
if (locationCells.isEmpty()) {
result = "kill";
}
else
{
result = "hit";
}
}
return result;
}
//TODO: all the following code was added and should have been included in the book
private String name;
public void setName(String string) {
name = string;
}
}
PS
I am referring heads first java book.
The ArrayList reference is being set in the setter method:
public void setLocationCells(ArrayList<String> loc)
{
locationCells = loc;
}
If this method is not called, and the reference not set before trying to use the ArrayList, then the code will throw a NullPointerException.
Side note: This does not look to be safe code, since it can be easily run incorrectly and so a NPE is easy to create. Better perhaps to set the ArrayList (List is even better) in a constructor.
How to pass multiple values to a single parameter for a particular method in java.
e.g. suppose i have a method with single parameter 'childname', that gets names of all the children in a family.
Now how can i pass multiple values to this parameter to get all different names.
public String getChildrenNames(String childname)
{
children= childname+ familyName;
return children;
}
You would typically implement this using either an Array, or a Collection.
eg:
public String[] getNamesOfChildren()
or
public Collection<String> getNamesOfChildren()
As people say you need to pass them as an Array, so your code should be like this:
String familyName = "Family";
public String[] getChildrenNames(String[] childnames)
{
String[] result = new String[childnames.length];
for(int i=0; i<childnames.length; i++)
{
result[i] = childnames[i] + " " +familyName;
}
return result;
}
public void main()
{
String[] childnames = {"Name1", "Name2", "Name3"};
String[] childnamesAux = getChildrenNames(childnames);
}
With this your childnamesAux variable should have: {"Name1 Family", "Name2 Family", "Name3 Family"}
If you can't change the signature of your method, then you can use concatenation, then in your method you can split this parameter for example :
String childname = firstname + "," + lastname;
getChildrenNames(childname);
so you can split this parametter to get multiple names,
String[] spl = childname.split(",");
But there are better ways then this, if you can change the signature of your method, so you can create a method which can take an array or list of names instead :
public String getChildrenNames(String...childnames) {
or
public String getChildrenNames(Lis<String> childnames) {
You can even create an Object for example :
class Person{
private String firstname;
private String lastname;
//getters and setters
}
Then your method should take an array or a list of Person Object :
public String getChildrenNames(List<Person> childname) {
You can try this
public static String child(String... name){
String[] array=name;
String tem;
if(name.length==1)
return name[0];
for(int counter=0; counter<array.length;counter+=2){
array[0]=name[counter]+name[counter+1];
}
tem=array[0];
return tem;
}
now if you call it
child("Paul","walker");
the output will be
Paul Walker
hope this helped
you can use var args like below
public String getChildrenNames(String... childname)
{
for(String s:childname)
{
children= childname+ s;
}
return children;
}
example
public class Test {
public static void main(String[] args) {
System.out.println(tes("s","d","s"));
}
static String tes(String... x)
{
String y="";
for(String s:x)
{
y=y+s;
}
return y;
}
}
output: sds
I have list of string data that are not change during any operation inside my program. But i need to access those data in several places by using key.
As a example: (1,ANN)(2,ALEX)(3,ANDROW)
Is there any way to store these data in separate class.Can I use java enum for this. thank you
With the use of enum you can implement something like below:
public enum Name {
ONE {
#Override
public String getName() {
return "ANN";
}
},
TWO {
#Override
public String getName() {
return "ALEX";
}
},
THREE {
#Override
public String getName() {
return "ANDROW";
}
};
public abstract String getName();
}
Then you can get the the names :
System.out.println(Name.ONE.getName());
This is really a good candidate for using Map. Where you can use your numbers as keys and String's as values.
https://docs.oracle.com/javase/tutorial/collections/interfaces/map.html
Map<Integer, String> map = new HashMap<Integer,String>();
Map<Integer,String> is one option and if key is also constant you could define string variable like
public static final string ONE = "ANN";
public static final string TWO = "ALEX";
A different way to use enums to define a statically mapping:
public enum Names {
ONE("ANN"),
TWO("ALEX"),
THREE("ANDREW");
private final String name;
private Names(String name){
this.name=name;
}
public String getName() {
return this.name;
}
}
This is only applicable to real-static values (change to values does mean a code change), but you can easily define multiple properties as well.
You can do the following:
import java.util.HashMap;
public class Main {
static HashMap<Integer,String>data = new HashMap<>();
public static void main(String[] args) {
// write your code here
data.put(data.size(),"ALEX"); // if you want 1-based indexing,
data.put(data.size(),"ANDROW"); // then use data.size()+1
data.put(data.size(),"ANN"); // instead of data.size()
for (int i = 0; i<data.size(); i++){
System.out.println(i+" : "+data.get(i)); // use i+1 if 1-based indexing
}
}
}
public class Example {
private static class Courses {
public final String name;
public final Courses[] children;
public Courses(String name, Courses ... children) {
this.name = name;
this.children = children;
}
}
public static void main(String[] args) {
Courses courses =
new Courses("School",
new Courses("Mathematics",
new Courses("Algebra"),
new Courses("Trig"),
new Courses("Calculus"),
new Courses("Calculus 2"),
new Courses("Geometry")),
new Courses("Sciences",
new Courses("Biology"),
new Courses("Chemistry"),
new Courses("Physics"),
new Courses("Business",
new Courses("Finances",
new Courses("Accounting"),
new Courses("Accounting 1"),
new Courses("Accounting 2"),
new Courses("Administration",
new Courses("Economics"),
new Courses("Business Studies"),
new Courses("Administration 1"),
new Courses("Accounting"))),
new Courses("Physical Education"))));
System.out.println(find(courses, "Economics", courses.name));
public static String find(Courses courses, String name, String currentPath) {
if((courses.name).equals(name)){
System.out.println(currentPath);
return currentPath + " / " + name;
}
else{
//System.out.println(currentPath);
for(Courses child:courses.children){
currentPath += " / " + child.name;
find(child, name, currentPath);
}
}
return currentPath + " / " + name;
}
}
So this is the code that I have acquired. I'm trying to determine what the right thinking pattern should be when coding this find courses method. This is an array but I'm thinking of it in like a tree like manner and trying to find the answer. IS that something you guys would do too? I'm trying to find a path like this School / Business / Administration / Economics. But either I'm getting the whole path or it's iterating through the whole thing. Also, what's the approach you guys will take to accomplish this. I wrote a recursive method to achieve this, but its not working out.
Thanks, for your help
CC
Thinking about it as a tree is obviously the way to go, as it is indeed a tree.
It might help you to think what you expect the method to do if the current value of courses was the parent of the node you want. That is in your case, if it's the Administration node. In your current implementation, you will iterate over all the children, never realizing you found the correct child!
As another hint, you would generally in recursion want to do something with the result of the recursive call. In your code, you call find(child, name, currentPath) and then you do nothing with the result!
Hope these hints help you.
Your question contains some opinion-based (sub)questions. These we cannot answer, but we can help with your recursive algorithm.
The if branch of your find method seems alright. It enters that branch when an exact match occurs. The problem is in your else branch, where you need recursion to keep looking in the children courses.
Note that your method declaration returns a String.
public static String find(Courses, String, String)
And note that, when you recursively call this function, you are ignoring its return value, rendering the recursive call useless.
for (Courses child: courses.children) {
currentPath += " / " + child.name;
find(child, name, currentPath); // <-- this return value is being ignored!
}
Start by assigning the return value of the recursive search to some variable, and define a return value for when the search doesn't find the provided name (you will not find Biology under Administration, for instance). I'll assume that an empty String means the search didn't find the course.
String result = find(child, name, currentPath);
if (!result.isEmpty()) {
// it has been found
}
Finally, note that you are changing the value of the currentPath variable on each iteration, by appending to it. That will result in erroneous paths, if the name is found after the first iteration. Assign that temporary path, for that iteration, to another variable.
I would do something like this
Course.java
public class Course {
private Course parentCourse;
private String name;
public Course(String name){
this.setName(name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Course getParentCourse() {
return parentCourse;
}
public void setParentCourse(Course parentCourse) {
this.parentCourse = parentCourse;
}
}
Courses.java
public class Courses {
private List<Course> courses;
public Courses(){
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
Main
Courses courses = new Courses();
List listCourses = new ArrayList<Course>();
Course generalMaths = new Course("General Maths");
Course linAlgebra = new Course("Linear Algebra");
linAlgebra.setParentCourse(generalMaths);
listCourses.add(generalMaths);
listCourses.add(linAlgebra);
courses.setCourses(listCourses);
Find path
for(Course course : courses.getCourses()){
StringBuffer coursePath = new StringBuffer();
coursePath.append(course.getName());
while(course.getParentCourse() != null){
course = course.getParentCourse();
coursePath.append(" | "+course.getName());
}
System.out.println(coursePath);
}
I am creating a helper class in parsing XML elements, so the developer do not need to know the exact name and capitalization of the XML fields.
private static class TagNames{
public static String RESOURCE_ID = "ResourceId";
public static String RESOURCE_NAME = "ResourceName";
public static String RESOURCE_PRICE = "ResourcePrice";
}
This makes it easier to do things like:
someXMLParser.getValueByTagName(TagNames.RESOURCE_ID);
My question is this. If I want to iterate over all the fields declared in class TagNames, how do I do that? Pseudocode:
For tag in TagNames:
someXMLParser.getValueByTagName(tag)
I know I will probably have to restructure all of this. But I can't figure out a way to make the names easily accessible as well as iterable, without any duplication.
Any suggestions?
You're literally asking for a solution based on reflection, but I think a Java Enum may be a better choice in this case. Building on Frederick's example:
public class EnumTest {
public enum Tags {
RESOURCE_ID("ResourceId"),
REOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice");
private final String tagName;
Tags(String tagName) {
this.tagName = tagName;
}
public String getTagName() {
return tagName;
}
}
public static void main(String[] args) {
for(Tags tag : Tags.values()) {
System.out.println("const:" + tag.name()
+ " tagName:" + tag.getTagName());
}
// API user might do e.g.:
// document.getValueForTag(Tags.REOURCE_NAME);
}
}
Although I agree that you should probably use enums or ResourceBundles, here's a solution to your actual question. A method that generates a Map name -> value from all public constants in a given class (the only thing that's missing should be try / catch or throws)
public static Map<String, Object> getConstantValues(Class<?> clazz){
Map<String, Object> constantValues = new LinkedHashMap<String, Object>();
for(Field field : clazz.getDeclaredFields()){
int modifiers = field.getModifiers();
if(Modifiers.isPublic(mod)
&& Modifiers.isStatic(mod) && Modifiers.isFinal(mod)){
constantValues.put(field.getName(), field.get(null));
}
}
return constantValues;
}
You may want to consider using a ResourceBundle instead of a class to store the tag names. May require a little bit of reworking of your code but it will be easier to produce a list of tags compared to what you are doing now, and adding a new tag won't require much work other then adding a line to the properties file.
You can do this quite easily using enum and an accompanying array:
public class Main {
public enum TagName { RESOURCE_ID, REOURCE_NAME, RESOURCE_PRICE }
private static String[] tags = {"ResourceID", "ResourceName", "ResourcePrice"};
public static String getValueByTagName(TagName tag) {
return tags[tag.ordinal()];
}
public static void main(String[] args) {
System.out.println("Calling by getValueByTagName:");
System.out.println(getValueByTagName(TagName.RESOURCE_ID));
System.out.println("Calling TagName.values() for loop:");
for (TagName t : TagName.values()) {
System.out.println(getValueByTagName(t));
}
}
}
Using an enum is a good fit, especially if you use a custom constructor and the built in "values" method:
public class Main {
public static enum TagName {
RESOURCE_ID("ResourceId"),
RESOURCE_NAME("ResourceName"),
RESOURCE_PRICE("ResourcePrice"),
;
private String s;
private TagName(String s) { this.s = s; }
public String toString() { return this.s; }
public static String[] strings() {
List<String> ss = new ArrayList<String>();
for (TagName tagName : TagName.values()) {
ss.add(tagName.toString());
}
return ss.toArray(new String[ss.size()]);
}
}
public static void main(String[] args) {
// Use TagName.values() for the enums, or for strings...
for (String s : TagName.strings()) {
System.out.println(s);
}
}
}
This way you can simply add new tags and they'll automatically get picked up by the "strings" method; for extra performance you could compute that string array just once, statically, since you can't change the set of enums dynamically. You could get even fancier by auto-generating the tag strings from their constant values, if they are really normalized...