Searching for a String in an Array of Objects - java

I have a Object that contains an ArrayList of self referntial objects. Each Object in that ArrayList contains the same structre upto n degrees. Now i have to search for a string in the structure and if found i have to print all the way up to the root. Here is a sample
MyClass {
string name;
ArrayList<MyClass> subClasses;
}
What data structure would be best to do this. Or do i not need one to use it.
Kind Regards

You could have a method on MyClass like below
public List<String> findPathOfName(String nameToFind) {
List<String> result = new ArrayList<String>();
if (nameToFind.equals(name)) {
result.add(name);
} else {
for (MyClass aSubClass: subClasses) {
List<String> subResult = aSubClass.findPathOfName(nameToFind);
if (!subResult.isEmpty()) {
result.add(name);
result.addAll(subResult);
break;
}
}
}
return result;
}
basically recursively go through the structure and find the path. Returned list would contain the path like personA/personB/etc..

This is http://en.wikipedia.org/wiki/Composite_pattern. Try my version
static class MyClass {
String name;
List<MyClass> subClasses;
MyClass(String name) {
this.name = name;
}
String search(String s, String path) {
if (!path.isEmpty()) {
path += "->";
}
path += name;
if (!s.equals(name)) {
if (subClasses == null) {
return null;
}
for (MyClass c : subClasses) {
return c.search(s, path);
}
}
return path;
}
}
public static void main(String[] args) throws Exception {
MyClass c1 = new MyClass("c1");
MyClass c2 = new MyClass("c2");
MyClass c3 = new MyClass("c3");
c1.subClasses = Arrays.asList(c2);
c2.subClasses = Arrays.asList(c3);
System.out.println(c1.search("c3", ""));
}
output
c1->c2->c3

Related

Create List of enum by field from comma separated String in Java

I have some enum and I need to create a List of enum from a comma-separated String. Enum is defined through an additional field. I have:
public enum ReceiverFields {
FIRST_NAME("firstName"),
LAST_NAME("lastName"),
MIDDLE_NAME("middleName");
private String code;
private ReceiverFields(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
public class MainClass {
public static void main(String[] args) {
List<EnumFields> enumFields = null;
enumFields = getReceiverFields("enumFirst,enumSecond,enumThird");
System.out.println(Arrays.toString(enumFields.toArray()));
enumFields = getReceiverFields("enumFirst,enumThird,somethingOther");
System.out.println(Arrays.toString(enumFields.toArray()));
enumFields = getReceiverFields("");
System.out.println(Arrays.toString(enumFields.toArray()));
}
public static List<EnumFields> getReceiverFields(String receiverFields) {
if (receiverFields == null) {
return Collections.EMPTY_LIST;
}
String[] values = receiverFields.split(",");
List<EnumFields> valuesList = new ArrayList<>(values.length);
for (String value : values) {
for (EnumFields enumField : EnumFields.values()) {
if (value.equalsIgnoreCase(enumField.getCode())) {
valuesList.add(enumField);
}
}
}
return valuesList;
}
}
How I can use stream instead of the loop For?
Edit (from the comments):
I seem to have decided:
List<EnumFields> valuesList = new ArrayList<>(values.length);
Arrays.stream(values).forEach(v -> (Arrays.stream(EnumFields.values())
.filter(e -> (e.getCode().equalsIgnoreCase(v)))
.findFirst()) .ifPresent(valuesList::add)); Right?
Instead of using forEach as mentioned in the attempt, you can make use of flatMap and ternary operator as :
public static List<ReceiverFields> getReceiverFields(String receiverFields) {
return receiverFields == null ? Collections.emptyList() : Arrays.stream(receiverFields.split(","))
.flatMap(value -> Arrays.stream(ReceiverFields.values())
.filter(enumField -> value.equalsIgnoreCase(enumField.getCode())))
.collect(Collectors.toList());
}

Sort Linked List based on dynamic field from user

My objective is to Dynamically insert values in to the Linked List. And thereafter, I want to perform sorting or search algorithms on the List.
In addition to it, I am creating class at runtime (based on user input) using Reflection.
Thereafter, I use data provided by the user in JSON Array, to create instances of the class, and then I insert the instances in to the GenericList.
Following is the code for the Generic Linked List.
public class LinkedListNode<T> implements Serializable {
private T value;
private LinkedListNode<T> next;
public LinkedListNode(T value) {
this.value = value;
}
public void setNext(LinkedListNode<T> next) {
this.next = next;
}
public LinkedListNode<T> getNext() {
return next;
}
public T getValue() {
return value;
}
}
public class GenericList<T> implements Serializable {
private LinkedListNode<T> first = null;
public void insert(LinkedListNode<T> node) {
node.setNext(first);
first = node;
}
public void emptyList(){
first = null;
}
public void remove(){
if(first.getNext()!=null)
first = first.getNext();
else first = null;
}
}
And this is how I create instances of the class and insert it to the GenericList.
//dataToInsert => is the JSONArray. => [{field1:"value1",field2:"value1"},{field1:"value2",field2:"value2"},{field1:"value3",field2:"value3"}]
//classLoaded => package com.LinkedAnalyzerAdapter.saveTestClasses; public class order implements java.io.Serializable {public String field1;public String field2;}
Class<?> classLoaded = classLoader.loadClass("com.LinkedAnalyzerAdapter.saveTestClasses.order");
GenericList<Object> list = new GenericList<Object>();
for (int i = 0; i < dataToInsert.length(); i++) {
JSONObject jsonObj = new JSONObject();
jsonObj = dataToInsert.getJSONObject(i);
Object obj = classLoaded.newInstance();
Field[] fs = classLoaded.getDeclaredFields();
for (Field field : fs)
{
field.setAccessible(true);
Object fieldValue = jsonObj.get(field.getName());
field.set(obj, fieldValue);
}
list.insert(new LinkedListNode<Object>(obj));
}
I am successfully able to insert data in to GenericList, but after inserting I later want to sort the data based on field1, in the ascending order.
I have spent hours to solve it but unable to successfully accomplish sorting.
You should really use java.util.LinkedList instead of your own GenericList, to take advantage of the built in Collections
LinkedList<LinkedListNode<?>> list = new LinkedList<>();
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return ...
}
}
Used the following code to resolve the issue.
public void sortLinkedList(final String fieldToCompare){
Collections.sort(testList, new Comparator<LinkedListNode>() {
#Override
public int compare(LinkedListNode arg0, LinkedListNode arg1) {
// TODO Auto-generated method stub
Field[] fs = classtoLoad.getDeclaredFields();
for (Field field : fs){
field.setAccessible(true);
Object fieldName = field.getName();
if(fieldToCompare.equalsIgnoreCase((String) fieldName)){
try {
String value1 = (String) field.get(arg0.getValue());
String value2 = (String) field.get(arg1.getValue());
return value1.compareToIgnoreCase(value2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return 0;
}
}
return 0;
}
});
}

Not sure how I am supposed to keep this Arraylist from being editable

I have this class, Party, in which I have an arraylist RSVP and an arraylist invited. The goal is that One should be able to add a name to these arraylists using my addInvited() and get it using getInvited(). I know the problem is in one of these two methods, as every other method has passed its test. I need to make it so that someone can add a Person object using addInvited(), but that Person CANNOT change his name. I can't seem to figure out if I'm just not making a deep enough copy, or what...
package lab04partB;
import java.util.ArrayList;
public class Party {
private ArrayList<Person> invited;
private ArrayList<Person> RSVP;
public Party() {
invited = new ArrayList<Person>();
RSVP = new ArrayList<Person>();
}
public void addInvited(Person person) {
if (!invited.contains(person)) {
Person JohnDoe = new Person(person.getName());
invited.add(JohnDoe);
}
}
public ArrayList<Person> getInvited() {
ArrayList<Person> tempList = new ArrayList<Person>(invited);
return tempList;
}
public void addRSVP(Person person) {
if ((!RSVP.contains(person)) && (invited.contains(person))) {
Person JaneDoe = new Person(person.getName());
RSVP.add(JaneDoe);
}
}
public ArrayList<Person> getRSVP() {
ArrayList<Person> tempList = new ArrayList<Person>(RSVP);
return tempList;
}
}
Here is the test it is running against, if it helps!
#Test
public void testGetInvitedModifyNamesReturned() {
Party party = new Party();
Person a = new Person( new String( KANY_GARCIA ));
Person b = new Person( new String( LAURA_PAUSINI ));
party.addInvited( a );
party.addInvited( b );
ArrayList<Person> list = party.getInvited();
assertEquals( 2, list.size() );
for (Person p : list) {
p.setName( new String( MIGUEL_RIOS ));
}
list = party.getInvited();
assertEquals( "Incorrect result", 2, list.size() );
assertTrue ( "Incorrect result", list.contains( a ));
assertTrue ( "Incorrect result", list.contains( b ));
}
One way would be to make the name field in the Person class final but then no one can change the name of a person anywhere. Guess that is not what you want.
Alternatively you can create an inner class in Party that subclasses Person and disallows changing the name. Then when you add a person to a party you first convert the input argument to an immutable person.
class Party {
private static final class ImmutablePerson extends Person {
public ImmutablePerson(String name) {
super(name);
}
#Override
void setName(String s) {
throw new RuntimeException("Cannot change name");
// or just do nothing here
}
}
public void addInvited(Person person) {
ImmutablePerson immutable = new ImmutablePerson(person.getName());
if (!invited.contains(immutable)) {
invited.add(immutable);
}
}
}
Make Person immutable. It's actually best practice too, because people don't change data, and (as here) you can safely publish them.
There's a few ways you might be able to do this...
You could use interfaces to maintain the contractual expectations of the API, so you could setup non-mutable version of Person (with getters) and a mutable version (with setters), this would mean that your Party class could return the non-mutable types, preventing people from directly modifying the values.
This could lead to using the non-mutable instance as a wrapper for the mutable version, further preventing people from casting the results to get around this.
Something like...
public interface Person extends Comparable<Person> {
public String getName();
}
public class DefaultPerson implements Person {
private String name;
public DefaultPerson(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof Person)) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 37 * hash + Objects.hashCode(this.name);
return hash;
}
#Override
public int compareTo(Person arg0) {
return arg0.getName().compareTo(name) * -1;
}
public Character[] toCharacterArray(String s) {
if (s == null) {
return null;
}
int len = s.length();
Character[] array = new Character[len];
for (int i = 0; i < len; i++) {
array[i] = new Character(s.charAt(i));
}
return array;
}
#Override
public String toString() {
return getName();
}
}
Then your Party might look something like...
public static class Party {
private ArrayList<Person> invited;
private ArrayList<Person> RSVP;
public Party() {
invited = new ArrayList<Person>();
RSVP = new ArrayList<Person>();
}
public void addInvited(Person person) {
if (!invited.contains(person)) {
invited.add(person);
}
}
public List<Person> getInvited() {
return Collections.unmodifiableList(invited);
}
public void addRSVP(Person person) {
if ((!RSVP.contains(person)) && (invited.contains(person))) {
RSVP.add(person);
}
}
public List<Person> getRSVP() {
return Collections.unmodifiableList(RSVP);
}
}
The class know only deals with Person types, which are not mutable (okay, you could create instances of DefaultPerson and add them to your lists, which would prevent the caller from modifying the names, but that's up to you)
The class also makes use Collections.unmodifiableList which prevents the List from been modified by the caller! Bonus :)
It would then mean, doing something like...
List<Person> list = party.getInvited();
for (Person p : list) {
p.setName(new String("Whelma"));
}
would be impossible, because setName is not a method of Person!
But...
that might be beyond the scope of your assignment, instead, when you return the list of invitees, you could create new instances of the values then, for example...
public void addInvited(Person person) {
if (!invited.contains(person)) {
invited.add(person);
}
}
public ArrayList<Person> getInvited() {
ArrayList<Person> tempList = new ArrayList<>(invited.size());
for (Person p : invited) {
tempList.add(new Person(p.getName()));
}
return tempList;
}
This is less the optimal, but it would allow your code to pass the tests you have.
I should also point out, equals has a contractual relationship with hashcode, from the JavaDocs:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
Basically, what this means is, if you override equals you must also override hashcode (and visa-versa)

Construct a class from HashMap

I want to write a constructor to set values from a HashMap. Can you please advise what is the best way to do this?
Write now I am using switch statement to call methods based on HashMap key, but I am wondering whether there is any better alternative.
FYI, in the myItems class, I actually have 25 variables to set.
public class MainClass{
BufferedReader br = new BufferedReader(new FileReader(file));
String[] datakey = br.readLine().split(";"); // getting header, 25 of them
HashMap<String,String> bookmap = new HashMap<String,String>();
String[] dataarr = line.split(";"); // getting values, 25 of them
int k = 0;
for(String d : datakey){
bookmap.put(d, dataarr[k++]); // Key-Value Pair
}
myItems item = new myItems(bookmap); // HOW TO WRITE THIS CONSTRUCTOR?
}
public class myItems {
String _id="";
String _name="";
String _genre="";
String _language="";
int _rating=0;
int _price=0;
...........................
...//25 OF THEM...
...........................
public myItems(HashMap<String,String> allrec){
Iterator<Map.Entry<String,String>> it = allrec.entrySet().iterator();
while(it.hasNext()){
Map.Entry pairs = (Map.Entry)it.next();
Switch(pairs.getKey()){
case "id":
setid(pairs.getValue());
break;
case "name":
setname(pairs.getValue());
break;
Deafult:
break;
}
}
}
public int getid(){
return this._id;
}
public String getname(){
return this._name;
}
..............................
..............................
..............................
public void setid(int id){
this._id = id;
}
public void setname(String name){
this._name = name;
}
..............................
..............................
..............................
}
Why don't you just write it strait forward like this:
public myItems(HashMap<String,String> allrec){
setid(allrec.get("id");
setname(allrec.get("name");
}
If you don't want any attribute to be assigned a null value then you should check if the Map returns a null:
public myItems(HashMap<String,String> allrec){
String id = allrec.get(id);
if(id != null)
setid(id);
// ...
}
There is actually another solution for your problem. Why bother storing those value in attributes anyway? You can just store them in the Map itself. Your constructor will be something like this:
private Map<String, String> mAttributes;
public myItems(HashMap<String, String> allrec) {
mAttributes = allrec;
}
Note that you should consider making a copy of the whole map instead of storing reference like above. Then write set methods like this:
public void setId(String id) {
mAttributes.put("id", id);
}
And your get methods are like this:
public String getId() {
return mAttributes.get("id");
}
You can use Reflection for that. Imagine that some fields have setters (okay for datastructures, questionable for classes - and what about mutability vs. immutability?), others haven't. Then you could do it like this:
import java.lang.reflect.Method;
public void setAll(final Map<String, String> fieldMap) {
for (final Map.Entry<String, String> entry : fieldMap.entrySet())
setField(entry);
}
public void setField(final Map.Entry<String, String> entry) {
setField(entry.getKey(), entry.getValue());
}
public void setField(final String name, final String value) {
final Method fieldSetter = getFieldSetter(name);
if (fieldSetter != null) {
fieldSetter.invoke(this, value);
return;
}
final Field field = getField(name);
if (field != null) {
field.set(this, value);
return;
}
// Throw some exception
}
public Method getFieldSetter(final String fieldName) {
return getMethod(getSetterName(fieldName));
}
public static String getSetterName(final String fieldName) {
return "set" + upperCaseFirst(fieldName);
}
public static String upperCaseFirst(final String s) {
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
}
public Method getMethod(final String methodName) {
final Class<?> clazz = getClass();
try {
return clazz.getMethod(methodName, String.class);
} catch (final NoSuchMethodException ignore) { }
try {
return clazz.getDeclaredMethod(methodName, String.class);
} catch (final NoSuchMethodException ignore) { }
return null;
}
public Field getField(final String fieldName) {
final Class<?> clazz = getClass();
try {
return clazz.getField(fieldName);
} catch (final NoSuchFieldException ignore) { }
try {
return clazz.getDeclaredField(fieldName);
} catch (final NoSuchFieldException ignore) { }
return null;
}
There are some exceptions to be handled, you will need to change the source code accordingly.
AFAIR on Android Reflection comes at a performance penalty. You might want to keep an eye on that method's performance.

how do I copy an object containing collections as fields

consider the below code:
public class Bid {
private double pe;
private List<ResChar> resourceList;
protected Map<Integer,Integer>scheduleOfSeller ;
public Map<Integer, Integer> getScheduleOfSeller() {
return scheduleOfSeller;
}
public void setScheduleOfSeller(Map<Integer, Integer> scheduleOfSeller) {
this.scheduleOfSeller = scheduleOfSeller;
}
private int bidId;
public int getBidId() {
return bidId;
}
public void setBidId(int bidId) {
this.bidId = bidId;
}
public double getPe() {
return pe;
}
public void setPe(double pe) {
this.pe = pe;
}
public List<ResChar> getResourceList() {
return resourceList;
}
public void setResourceList(List<ResChar> resourceList) {
this.resourceList = resourceList;
}
public Bid(int bidId,double pe, List<ResChar> resourceList){
setBidId(bidId);
setPe(pe);
setResourceList(resourceList);
this.scheduleOfSeller = new HashMap<Integer,Integer>();
}
}
I want to make a copy constructor of the bid like this :
public class BidCopy{
public Bid bid;
public BidCopy(Bid bidBuyer){
List<ResChar> resList = new LinkedList<ResChar>();
for (ResChar elt : bidBuyer.getResourceList()){
ResCharCopy eltCopy = new ResCharCopy(elt);
resList.add(eltCopy.elt);
}
this.bid = bidBuyer;
this.bid.setResourceList(resList);
}
}
The only solution that I know to make such copy is to proceed like follows :
public class BidCopy{
public Bid copy;
public BidCopy(Bid bid){
List<ResChar> resList = new LinkedList<ResChar>();
for (ResChar elt : bid.getResourceList()){
ResCharCopy eltCopy = new ResCharCopy(elt);
resList.add(eltCopy.elt);
}
this.copy = new Bid(bid.getBidId(), bid.getPe(), resList);
}
}
So I want to know if there is any other solution to make a copy of "Bid" Object more effectively ?
I would suggest making a copy constructor for your Bid object (and not a specific class for copying), a Bid is made out of its fields and not methods, like so:
public class Bid {
int ID;
String description;
Object bidStuff;
// ...as before
public Bid(Bid bid) {
this.ID = bid.ID;
this.description = bid.description;
this.bidStuff = bid.bidStuff;
}
public static void main(String[] args) {
List<Bid> original = new ArrayList<>();
// ..populate it
List<Bid> copy = new ArrayList<>(original.size());
for (Bid b : original) {
copy.add(new Bid(b));
}
}
}
You can even make the copy constructor protected or package-protected if you don't want anyone else to mess around with making multiple copies of bids.
There is not. Even though some collections have "copy constructors", these constructors will copy the elements' references, they will not create new elements for you.
You can however "optimize" the list creation itself by submitting the size of the initial list to the constructor:
List<X> newList = new LinkedList<X>(oldList.size());

Categories