I have two ArrayLists:
private ArrayList<MenuItemBean> newList= new ArrayList<MenuItemBean>();
private ArrayList<MenuItemBean> newGroupList= new ArrayList<MenuItemBean>();
In one function I am adding data to one ArrayList:
public void setConfirmList(List<MenuItemBean> cList){
newList.addAll(cList);
listAdapter=new ListAdapter(context, newList);
lv_item.setAdapter(listAdapter);
}
Another function where I am just grouping data (increasing quantity if product is already exist) using for-loop and adding data to a second ArrayList. But my problem is as I increase quantity in ArrayList2, my quantity in ArrayList1 itself modifies. I know its because of same reference of objects. Can we change this behavior by any way.
private void groupList() {
newGroupList.clear();
ArrayList<MenuItemBean> mList= new ArrayList<MenuItemBean>();
mList.addAll(newList);
for (int i = 0; i < mList.size(); i++){
String productId = mList.get(i).getProductId();
if(newGroupList.size()==0){
newGroupList.add(mList.get(i));
}else{
Boolean bool=false;
for (int j = 0; j< newGroupList.size(); j++){
if(productId.equalsIgnoreCase(newGroupList.get(j).getProductId())){
bool= true;
// MenuItemBean newObject = new MenuItemBean();
// BeanUtils.copyProperties(newObject, newGroupList.get(j));
MenuItemBean bean= newGroupList.get(j);
int quantity = Integer.parseInt(bean.getUserQuantity());
Double sellingPrice = Double.parseDouble(bean.getSellingPrice());
quantity = quantity + 1;
sellingPrice = sellingPrice * quantity;
bean.setUserQuantity(String.valueOf(quantity));
bean.setUserPrice(String.valueOf(sellingPrice));
newGroupList.set(j, bean);
break;
}
}
if(!bool){
newGroupList.add(mList.get(i));
}
}
}
listAdapter=new ListAdapter(context, newGroupList);
lv_item.setAdapter(listAdapter);
}
I also tried by making copy of ArrayList by using
ArrayList newGroupList= new ArrayList<MenuItem>(newList);
But no help it simple copies data but not the reference. I tried but do not get any example to implement this.
But no help it simple copies data but not the reference.
You're right. By create new list and add data item to new list it's not copy object memory. Both item in those list point to same memory address in heap. So when you modify data item in one of those list. This affects others data item too. for example
public static void main(String[] args) {
List<ObjectItem> datas = new ArrayList<ObjectItem>();
ObjectItem obj1 = new ObjectItem();
obj1.setId(1);
datas.add(obj1);
System.out.println("memory addrs for obj1:" + datas.get(0)); //memory addrs for obj1: 533e846f
List<ObjectItem> other_datas = new ArrayList<ObjectItem>();
other_datas.addAll(datas);
System.out.println("memory addrs for obj1:" + other_datas.get(0));//memory addrs for obj1: 533e846f
}
If you want to solve your problem, let's make deep copy data. For example:
public class ObjectItem {
public ObjectItem(ObjectItem other) {
this.id = other.getId();
}
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
And then using it
List<ObjectItem> new_datas = new ArrayList<ObjectItem>();
for (int i = 0; i < datas.size(); i++) {
new_datas.add(new ObjectItem(datas.get(i)));
}
Related
I've read up on the wiki page on creating a extendable hashtable Extendable Hashing. And now i'm trying to implement that into a program to better understand it but I can't figure out how to actually point the directories towards the buckets.
Directory class:
int GlobalDepth = 1;
int directories[];
public Directory() {
int temp = (int)Math.pow(2, GlobalDepth);
loadDirectories(temp);
}
public void loadDirectories(int n) {
for (int i = 0; i < n; i ++) {
String BinaryKey = Integer.toBinaryString(i);
String tempKey = BinaryKey.substring(0, this.GlobalDepth); // LSB
int depthKey = Integer.parseUnsignedInt(tempKey);
this.directories[i] = depthKey;
}
}
public void increaseGlobalDepth() {
this.GlobalDepth ++;
loadDirectories((int)(Math.pow(2, this.GlobalDepth))); // This method might throw an error because i think im changing the array size illegally and should instead create a temp array and copy/equal that array to this.directories
}
Bucket class:
private SomeObject[] item; // Class I'm using to hold all the information of something
private int Key, MaxBucketsize, LocalDepth = 1;
//Bucket next;
public Bucket() {
}
public Bucket(int BucketSize) {
this.item = new SomeObject[BucketSize]; // Initalises the number of items held in the bucket
this.MaxBucketsize = BucketSize; // Stores the max number of items that can be held in the bucket
}
public SomeObject[] getObjects() {
return this.item;
}
public boolean addObjects(int key, SomeObject item) {
boolean inserted = false;
for (int i = 0; i < this.MaxBucketsize; i ++) {
if (this.item[i] == null) { // only inserts if there is an empty spot in the bucket
this.item[i] = item;
this.item[i].setKey(key);
inserted = true;
break;
}
}
return inserted;
}
After doing all this, I'm not sure how to now link the 2 together like in the wiki page.
public class CustomerManager {
private customer[] list;
private int maxcustomer;
private int numcustomer;
public CustomerManager(int size){
maxcustomer = size;
numcustomer = 0;
list = new customer[size];
}
//add customer
public boolean addcustomer(String Address, String Name){
customer x = new customer(Address, Name);
if(numcustomer < maxcustomer){
list[numcustomer] = x;
return true;
}
return false;
}
The list customer method is not listing customers
I assume its because data isn't properly being passed through to the managers but not exactly sure where I went wrong
public String listcustomer(){
String s = " ";
int i;
for(i = 0; i < numcustomer; i++){
s += list[i].getname();list[i].getaddress();
}
return s;
}
}
Hi and welcome to stackoverflow.
Couple things - when writing java
classes should start with Capital letter, while variables and functions with small letter.
Second when adding new customer you have to increase counter
public boolean addcustomer(String address, String name){
Customer x = new Customer(address, name);
if(numcustomer < maxcustomer){
list[numcustomer] = x;
numcustomer++;
return true;
}
return false;
}
But instead of it I would recommend storing customers in Collection like List or Set ( to prevent duplicates ).Then you won't have to worry about increasing counter, as you will have it built in.
private Set<Customer> customers;
public CustomerManager(int size){
maxcustomer = size;
customers = new HashSet();
}
public boolean addcustomer(String address, String name){
Customer newCustomer = new Customer(address, name);
if(customers.size() < maxcustomer){
customers.add(newCustomer)
return true;
}
return false;
}
To ensure Set won't store duplicates, you have to properly implement hashCode and equals more info
I would like to convert the following code from array to any other way (the most important is effective) which means that there is infinite space and I will not have to set the length of the array.
How can this be done? How can I set up an unlimited cities? using LinkedList
The idea is that it is possible to define a certain country in which certain cities are stored (the name of the city, the city center, the central bus station,... - as in the picture below) - In my code MAX_NUM_CITIES = 1000;
My Code:
public class Country {
//instance variables
private String _countryName; // name of the country
private City[] _cities; // Array of the cities
private int _noOfCities; //number of cities in a country
public void CityArray() {
_cities = new City[MAX_NUM_CITIES];
_noOfCities = 0;
}
//constants:
public final int MAX_NUM_CITIES = 1000;
/**
* Constructer for object in Country class construct Country with info accordingly
* #param countryName represents the name of country
* #param cities represents the cities array
* #param noOfCities represents the number of cities
*/
public Country(String countryName) {
this._countryName = _countryName;
this._noOfCities = _noOfCities;
City[] cities = new City[MAX_NUM_CITIES];
}
boolean addCity(java.lang.String cityName, double XcityCenter, double YcityCenter, double XStationPoint, double YStationPoint, long numOfResidents, int numOfNeighborhoods) {
if (_noOfCities <= MAX_NUM_CITIES) return false;
_cities[_noOfCities++] = new City(cityName, XcityCenter, YcityCenter, XStationPoint, YStationPoint, numOfResidents, numOfNeighborhoods);
return true;
}
public long getNumOfResidents() {
long SumOfCities = 0;
if (_noOfCities > 0) //empty Array
{
SumOfCities = _cities[0].getNumOfResidents();
for (int i = 1; i < _noOfCities; i++)
SumOfCities += _cities[i].getNumOfResidents();
} else
SumOfCities = 0;
return SumOfCities;
}
public String getCountryName() {
return this._countryName;
}
public int getNumOfCities() {
return this._noOfCities;
}
public City[] getCities() {
int noOfCities = this._noOfCities;
City[] cities = new City[noOfCities];
for (int i = 0; i < _noOfCities; i++) cities[i] = new City(this._cities[i]);
return cities;
}
public String toString() {
if (_noOfCities == 0) //empty Array
System.out.println("There are no cities in this country ");
else
for (int i = 0; i < _noOfCities; i++) _cities[i].toString();
return toString();
}
}
I would step away from arrays if the length is:
unknown
can change
I suggest using one of the different List implementations from the JDK, specifically ArrayList and LinkedList.
The first uses an internal array which may be expanded if an element is added and would lead to the array being too small (it does this all by itself, so no need to worry).
The second is a node list, which means that for every element you add, a new (internal) node object is appended to the last node.
You'd of course have to change your code for this.
Define your _cities to be a List<City>: private List<City> _cities
Initialize that with the wanted implementation in the constructor: _cities = new ArrayList<>(); or _cities = new LinkedList<>();
In your add method you can just call: _cities.add(new City(cityName, XcityCenter, YcityCenter, XStationPoint, YStationPoint, numOfResidents, numOfNeighborhoods));
In your getNumOfResidents you can use the following snippet (which uses Java streaming api introduced in java 8):
return _cities.stream()
.mapToLong(City::getNumOfResidents)
.sum();
for getCities() you'd have to change the return type to List<City> and use the following: return new ArrayList<>(_cities) or return new LinkedList<>(_cities) depending on the implementation you want to use.
Good day,
Here is my code:
public class ArrayDirectory implements Directory {
private int allocatedSize = 0;
public Entry[] entryDirectory = new Entry[allocatedSize];
#Override
public void addEntry(Entry newEntry) {
newEntry = findFreeLocation();
entryDirectory = Arrays.copyOf(entryDirectory,
entryDirectory.length + 1);
}
private Entry findFreeLocation() {
Entry returnedEntry = new Entry();
for (int i = 0; i < entryDirectory.length; i++) {
if (entryDirectory[i] == null) {
break;
}
returnedEntry = entryDirectory[i];
}
return returnedEntry;
}
I've made the size of the entryDirectory dynamic; it increments each time the addEntry method is used. However, when I am trying to call a method of an entry object from the entryDirectory array, a NullPointerException is thrown.
public static void main(String[] args) {
ArrayDirectory d = new ArrayDirectory();
d.addEntry(new Entry("Jack", "Jones", 1234));
d.addEntry(new Entry("Brad", "Jones", 1234));
d.addEntry(new Entry("Olga", "Jones", 1234));
System.out.println(d.entryDirectory[0].getInitials());
}
Here is the getInitials() method of the Entry object.
public Entry(String surname, String initials, int extension){
this.surname = surname;
this.initials = initials;
this.extension = extension;
}
public String getInitials() {
return initials;
}
You never assign anything as element of your array entryDirectory, so NullPointerException arises when you try to invoke getInitials() on null-value object entryDirectory[0].
Remember that if you use Arrays.copyOf(),
for any indices that are valid in the copy but not the original, the
copy will contain null
See Arrays javadoc
In addition to Philip Voronov's answer, your findFreeLocation method is also implemented incorrectly. Assuming null means an absence of value, the proper implementation should be like this:
private int findFreeLocation() {
for (int i = 0; i < entryDirectory.length; i++) {
if (entryDirectory[i] == null) {
return i
}
}
return -1;
}
You can then use it like this:
public void addEntry(Entry newEntry) {
int loc = findFreeLocation();
if (loc >= 0) {
entryDirectory[loc] = newEntry;
} else {
entryDirectory = Arrays.copyOf(entryDirectory, entryDirectory.length + 1);
entryDirectory[entryDirectory.length - 1] = newEntry;
}
}
That said, I highly suggest you use a built-in collection, like ArrayList, to handle automatically resizing arrays. They are much easier to use, and their performance is also better (increasing the array size by one means you have to resize every time an item is added, in comparison to ArrayList's implementation, which doubles the size every time it fills up).
what's the most efficient way (best performance and least gc) to store unique sorted values in Java?
Currently I use a HashMap to get a collection of unique values then I copy the HashMap values into a ArrayList then use Collections.sort() to sort the values as my objects implement Comparable which finally gives me a unique sorted values. The code will be run thousands of times a second so I want the best approach. Can anyone suggest a better alternative?
/The code will only be run in a single thread.
My code is below:
public class LapRanking {
private final Map<String, Car> carsInRace = new HashMap<String,Car>();
public List<Car> processLap(Car car){
carsInRace.put(car.driverName, car);
List<Car> lapTimeRankings = new ArrayList<Car>(carsInRace.values());
Collections.sort(lapTimeRankings);
return lapTimeRankings;
}
public static void main(String[] args) {
Car one = new Car("DriverOne");
Car two = new Car("DriverTwo");
Car three = new Car("DriverThree");
LapRanking lapRanking = new LapRanking();
for (int i = 0; i < 100; i++) {
one = one.setLapTime();
two = two.setLapTime();
three = three.setLapTime();
lapRanking.processLap(one);
lapRanking.processLap(two);
lapRanking.processLap(three);
}
}
}
public class Car implements Comparable<Car> {
private static final Random randomTestTimes = new Random();
public final String driverName;
public final double lapTime;
public final double firstQuarterTime;
public Car(String driverName) {
this.driverName = driverName;
this.lapTime = Double.MAX_VALUE;
this.firstQuarterTime = Double.MAX_VALUE;
}
public Car(String driverName, double lapTime, double firstQuarterTime) {
this.driverName = driverName;
this.lapTime = lapTime;
this.firstQuarterTime = firstQuarterTime;
}
public Car setLapTime(){
return new Car(driverName,randomTestTimes.nextDouble(), randomTestTimes.nextDouble());
}
#Override
public int compareTo(Car o) {
int i = Double.compare(lapTime, o.lapTime);
if(i !=0)
return i;
return Double.compare(firstQuarterTime, o.firstQuarterTime);
}
#Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append("Car {driverName='").append(driverName).append('\'');
sb.append(", lapTime=").append(lapTime);
sb.append(", firstQuarterTime=").append(firstQuarterTime).append('}');
return sb.toString();
}
}
You should think about using TreeMap or TreeSet.
http://docs.oracle.com/javase/7/docs/api/java/util/TreeMap.html
http://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html
They might be a good fit for your case.
As far as I can tell, for the application as written, the map actually serves no useful purpose. IMO, the most performant solution would be to replace the map with an Car[] of the appropriate size pre-allocated and populated on startup. Then do an in-place sort of the cars once each lap using Arrays.sort().
This satisfies your requirement. It is storing unique objects (the Car objects) and keeping them sorted.
There should be no garbage generated after startup, apart (possibly) for garbage created by the sort(...) method itself ... and in outputting the rankings.
Something like this:
Car[] cars = new Car[] {one, two, three};
for (int i = 0; i < 100; i++) {
one.setLapTime();
two.setLapTime();
three.setLapTime();
// Sort the cars based on their `compareTo` method; i.e. lap time.
Arrays.sort(cars);
// Output the cars, ranked by lap time
for (Car car in cars) {
...
}
}
Updated for the variant where the Car is immutable:
Car[] cars = new Car[3];
for (int i = 0; i < 100; i++) {
one = one.setLapTime();
two = two.setLapTime();
three = three.setLapTime();
cars[0] = one;
cars[1] = two;
cars[2] = three;
Arrays.sort(cars);
}
Or ... more concisely:
Car[] cars = new Car[]{one, two, three};
for (int i = 0; i < 100; i++) {
for (j = 0; j < cars.length[]; j++) {
cars[j] = cars[j].setLapTime();
}
Arrays.sort(cars);
}
(Though I must say that a setter that actually creates and returns a new object is pretty poor interface design. If I was code reviewing that code, there would be a LOT of red writing all over it ...)
By the way, the idea of using a TreeMap doesn't help, because your algorithm is actually sorting the map's value set not the key set.
I haven't timed it or done any benchmarking, but I strongly suspect that you'll get the biggest speedup by eliminating the "new" allocation of the ArrayList in processLap. Memory allocations are far more expensive than a sort on a 3 item list.
If you haven't added any cars between successive calls to processLap, then there's really no need to copy the values from the HashMap into an allocated ArrayList over again. Just sort the ArrayList you already had.
public class LapRanking {
private final Map<String, Car> carsInRace = new HashMap<String,Car>();
ArrayList<Car> lapTimeRankings;
public List<Car> processLap(Car car){
Car oldcar = carsInRace.put(car.driverName, car);
if (oldcar == null)
{
lapTimeRankings = new ArrayList<Car>(carsInRace.values());
}
Collections.sort(lapTimeRankings);
return lapTimeRankings;
}
And as someone else has already said - the need for the hash table is suspicious as well.
If you can have a separate function for inserting cars into the race rather overloading processLap, then you'll be even better....
public class LapRanking {
private final Map<String, Car> carsInRace = new HashMap<String,Car>();
boolean isDirty;
ArrayList<Car> lapTimeRankings;
void insertCarIntoRace(Car car)
{
carsInRace.put(car.driverName, car);
isDirty = true;
}
public List<Car> processLap(Car car){
if (isDirty)
{
lapTimeRankings = new ArrayList<Car>(carsInRace.values());
isDirty = false;
}
Collections.sort(lapTimeRankings);
return lapTimeRankings;
}
public static void main(String[] args) {
Car one = new Car("DriverOne");
Car two = new Car("DriverTwo");
Car three = new Car("DriverThree");
LapRanking lapRanking = new LapRanking();
lapRanking.insertCarIntoRace(car1);
lapRanking.insertCarIntoRace(car2);
lapRanking.insertCarIntoRace(car3);
for (int i = 0; i < 100; i++) {
one.setLapTime();
two.setLapTime();
three.setLapTime();
lapRanking.processLap(one);
lapRanking.processLap(two);
lapRanking.processLap(three);
}
}
}