ArrayList from class objects simpler way to do? - java

I know how to put class objects to an ArrayList in java (since new objects can be appended without knowledge of an index first) but I was wondering if there is a simpler way of adding them to an ArrayList and iterating over them?
I was even thinking that, hypothetically, if I kept my object names in a pattern, that I should be able to add each object to the list using a loop e.g. car1, car2, car3, ...
import java.util.ArrayList;
public class TestCar {
public static void main(String[] args) {
ArrayList<String> carNames = new ArrayList<>();
// Cars have simple getter methods corresponding with String and int
Car car1 = new Car("Rav4", 2017);
carNames.add(car1.getName());
Car car2 = new Car("Commodore", 2005);
carNames.add(car2.getName());
for (int i = 0; i < carNames.size(); i++) {
System.out.println(carNames.get(i));
}
}
}
As always, thanks for any replies!

Assuming you are using Java 8 or higher, you could add your Car objects to a list and use streams to get a list of carNames :
List<Car> myCarList = Arrays.asList( new Car("Rav4", 2017), new Car("Commodore", 2005));
List<String> carNames = myCarList.stream()
.map(Car::getName)
.collect(Collectors.toList());

Related

Java comparing two arrays with different structures but some similar items

I would like to compare two arrays. I have the following
ArrayList<String> time_durations = new ArrayList<String>();
time_durations.add("1200-1304")
time_durations.add("6-7")
Then the other array has the following structure
ArratList<FetchedData> apiresult = new ArrayList<FetchedData>();
apiresult.add(new FetchedData("1200-1304", //an array of data))
The class fetched data has
class FetchedData{
private String duration_range;
private ArrayList data;
//then setters and getters
//and also a constructor
}
So i want to compare the two arrays and get all items contained in time_durations but not in apiresult
Samples of them both in a json format is
time_durations = ["1200-1304", "6-7"]
apiresult = [{duration_range:"1200-1304", data:["item1", "item 2"]}
So by comparison i expect it to return the item in array time_durations6-7 that is index 1
So i have tried
if (Arrays.equals(time_durations, apiresult)) {
//this throws an error
}
But the above attempt doesnt work and am stuck.How do i achieve this?
I have checked on This question but still fails
Your code doesn't work as you expected because the first ArrayList is an array of String and the second is an Array of FetchedData. You basically try to compare two ArrayList of different type and this return false by default.
If you want to reach the goals you must map the ArrayList of FetchedData into an ArrayList of String and with Java8 it is possible to do this with a Map function and after you are enable to comparing the two array
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertArrayEquals;
public class TestClass {
#Test
public void arrayListComparation(){
List<String> expected = Arrays.asList("6-7");
ArrayList<String> time_durations = new ArrayList<String>();
time_durations.add("1200-1304");
time_durations.add("6-7");
ArrayList<FetchedData> apiresult = new ArrayList<>();
List<String> data = Arrays.asList("item1","item2");
apiresult.add(new FetchedData("1200-1304", data));
List<String> apiResultDurationRanges = apiresult.stream().map(FetchedData::getDuration_range).collect(toList());
time_durations.removeAll(apiResultDurationRanges);
assertArrayEquals(time_durations.toArray(),expected.toArray());
}
}
In this example you have on time_durations all element that not appear into apiResult
Iterate over the API results, get each duration and put them into a set. Remove the elements of the set from the list.
Set<String> apiDurations = apiresult.stream()
.map(FetchedData::getDuration)
.collect(Collectors.toSet());
time_durations.removeAll(apiDurations);
You can use Collection.removeAll:
List<String> apiResult_durations = apiresult.stream()
.map(FetchedData::getDuration_range)
.collect(Collectors.toList());
time_durations.removeAll(apiResult_durations);
After this code, time_durations is only [6-7]
Important to note that this will modify time_durations inline.
If you'd rather not modify it inline, then you can make a copy:
List<String> time_durations_copy = new ArrayList<>(time_durations);
time_durations_copy.removeAll(apiResult_durations);
I think you need the operation of set difference.
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> time_durations = new ArrayList<String>();//The list with some elements
ArrayList<String> otherList = new ArrayList<String>();//Another list
ArrayList<String> difference = new ArrayList<String>();//The result
time_durations.add("1200-1304");//Add some data
time_durations.add("6-7");
otherList.add("1200-1304");
for (int i = 0; i < time_durations.size(); i++) {
if (!otherList.contains(time_durations.get(i))) {
difference.add(time_durations.get(i)); // get all items contained in time_durations but not in apiresult
}
}
for (String string : difference) {
System.out.println(string);
}
}
}

How can I sort my arraylist named "serviceNeedingTasks" based on two attributes of an object [duplicate]

I want to sort a List of objects by a specified attribute of those objects and I want to choose which attribute should be used for sorting. Example:
class Car{
private String name;
private String colour;
public enum sortBy {NAME, COLOUR};
public String name(){
return name;
}
public String colour(){
return colour;
}
public static Car[] getSortedArray(Car[] carArray, sortBy sortType){
HashMap<Object, Car> carMap = new HashMap<Object, Car>();
Object[] sortArray = new Object[carArray.length];
Object value = null;
for(int i = 0; i < carArray.length; i++){
if(sortType == sortBy.NAME){
value = carArray[i].name();
}else if(sortType == sortBy.COLOUR){
value = carArray[i].colour();
}
carMap.put(value, carArray[i]);
sortArray[i] = value;
}
Arrays.sort(sortArray);
Car[] sortedArray = new Car[sortArray.length];
for(int i = 0; i < sortArray.length; i++){
sortedArray[i] = carMap.get(sortArray[i]);
}
return sortedArray;
}
}
//external:
Car[] cars = getSomeCars();
Car[] nameSortedCars = Car.getSortedArray(cars, Car.sortBy.NAME);
Car[] colourSortedCars = Car.getSortedArray(cars, Car.sortBy.COLOUR);
The idea is simple:
I put all values that i want to sort by into an array, and i create a map that maps these values back to their objects. After I sorted this array I take the objects mapped to these values and put them in the same order into a new array which is then sorted by these values. The values are just created with type Object so I can sort by multiple types (not just Strings as in the example).
This works fine unless you have two objects with the same attribute value, then only one object will be in the returned array, but two times.
Is there a better way to achieve this sorting?
It would be much simpler to use custom comparators:
To sort by name:
Arrays.sort(carArray, Comparator.comparing(Car::name));
To sort by colour:
Arrays.sort(carArray, Comparator.comparing(Car::colour));
So you could modify getSortedArray():
public static Car[] getSortedArray(Car[] carArray, Comparator<Car> comparator) {
Car[] sorted = carArray.clone()
Arrays.sort(sorted, comparator);
return sorted;
}
And call it like this:
Car[] sorted = getSortedArray(carArray, Comparator.comparing(Car::name));
Edit:
If you use a language version that does not support these features, you can create the comparators by explicitly creating a nested class that implements the Comparator interface.
This, for example, is a singleton Comparator that compares Car instances by name:
static enum ByName implements Comparator<Car> {
INSTANCE;
#Override
public int compare(Car c1, Car c2) {
return c1.name().compareTo(c2.name());
}
}
Then call:
Car[] sorted = getSortedArray(carArray, ByName.INSTANCE);
TL;DR: There's already a wheel for that.
I would say the easiest way to do this is to create a comparator:
final Comparator<Car> byName = Comparator.comparing(Car::name);
final Comparator<Car> byColour = Comparator.comparing(Car::colour);
Then just use the appropriate method on Arrays to sort by a comparator:
Arrays.sort(carArray, byName);
Now you want to do it with an enum? Just have the enum implements Comparator<Car>:
enum SortBy implements Comparator<Car> {
NAME(Comparator.comparing(Car::name)),
COLOUR(Comparator.comparing(Car::colour));
private final Comparator<Car> delegate;
private SortBy(Comparator<Car> delegate) {
this.delegate = delegate;
}
#Override
public int compare(final Car o1, final Car o2) {
return delegate.compare(o1, o2);
}
}
Want to sort by name then by colour? Easy:
final Comparator<Car> byName = SortBy.NAME.thenComparing(SortBy.COLOUR);
Want to sort by name in reverse order? Easy:
final Comparator<Car> byName = SortBy.NAME.reversed();
You're reinventing the wheel! Life will be much easier for you if you use the templated Collections API. To do this, you would work with List instead of arrays, define a Comparator to do your sorting, and then let the API do the work for you.
Comparator<Car> carComparator = new Comparator<Car>(){
public int sort(Car car1, Car car2){
//Sorting logic goes here.
}
}
List<Car> cars = getCars();
cars = Collections.sort(cars, carComparator); //the cars collection is now sorted.
If you wanted to sometimes sort by one attribute or another, you could make my variable carComparator into its own class and define which attributes to sort by in the constructor.
Hope that helps :)
Edit: As others have pointed out, this approach also works with arrays. But unless you have a good reason to be working with Arrays, working with Collections will generally be easier.
I think the solution would be more efficient if you passed a Comparator implementation to the Arrays.sort. Right now, you are looping n*2 from the looks of it, the hash map (O(1)) plus the Arrays.sort (which is another 0(n log n) or such). If you do the below, you could skip the 2 loops, and the map, you are using currently.
You can simply create a Comparator like (rough code):
class CarComparator implements Comparator<Car> {
enum compareType; //plus setter
public int compareTo(Car a, Car b) {
if(compareType == COLOUR) return a.colour.compareTo(b.colour);
if(compareType == NAME.....
}
}
, and then simply send the array of Cars to
Arrays.sort(cars, new CarComparator(COLOUR))
, or use more specialised comparator classes, one for each attribute, and a factory to render them, and of course don't create a new Comparator() for each sort if this is happening often. :-)
Overall, this approach should make your code more efficient.
}

How to count the amount of each object in an array list (Java)?

I am a beginner in Java so this may be a very basic question but I haven't been able to find an answer anywhere.
I would like to know how do you count the amount of each object in an array list, where the items are not named in the code?
I have 2 classes, one to simulate a vending machine, and the other representing the snacks. The constructor of the snacks class initiates the snack type as a string type as so:
public TypeOfSnack(String SnkType)
Then in the vending machine class these can be added onto the arraylist. The field for this is:
private ArrayList<TypeOfSnack> snacks;
I know to get the number of snacks in the array list by doing snacks.size(); But how do I return the amount of each type. So far I have done:
public int countSnacks(String SnkType)
{
return packets.size();
}
Which is just given me the total amount rather than the one passed through the method.
Thanks
You could convert the actual list to a unique item list and after that, you could use the method Collections.frequency to know how many time the same element appears in the list.
Example:
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(5);
numbers.add(5);
numbers.add(3);
numbers.add(5);
numbers.add(5);
numbers.add(2);
numbers.add(5);
Map<Integer, Integer> result = new HashMap<>();
for(Integer unique : new HashSet<>(numbers)) {
result.put(unique, Collections.frequency(numbers, unique));
}
System.out.println(result);
}
Output:
{2=1, 3=1, 5=6}
As far as i understand, you want to store the number of each snack in an ArrayList.
An ArrayList is not suitable for this problem, you should use HashMap.
Maybe something like the following code:
HashMap<String, Integer> snacks = new HashMap<String, Integer>();
snacks.put("Chips", 5);
snacks.put("Fried", 2);
To get the number of a snack:
int numberOfChips = snacks.get("Chips");
Or if you want to do it your way:
public int getNumberOf(String snackType) {
int value = 0;
for(TypeOfSnack s : snacks) {
if(s.getType().equals(snackType)) {
value++;
}
}
}

ArrayDeque add multiple elements

Im using arraydeque to create list of items and pass them parameters(Items is class)
ArrayDeque<Item> Items= new ArrayDeque<Item>();
But I have problem with java ArrayDeque. Maybe there are ways to add more than one element at once.
For example. I want add at the same time TableType and colourOfTable into ArrayDeque.
In c++ I could have done it with this
vector<Item>Items
Items.push_back(Item("CoffeeTable", "brown"));
I want to do the same thing with Java. Instead of creating a new obj for every item, as:
ArrayDeque<Item> Items = new ArrayDeque<Item>();
Item obj = new Item("CoffeTable", "brown");
Items.add(obj);
Item obj1 = new Item("DinnerTable", "Black");
Items.add(obj1);
But instead of obj I want to add "CoffeTable", "brown" at the same time and with one code line (like in c++ example) into the Items array.
I tried something like that
ArrayDeque<Item> Items= new ArrayDeque<Item>();
Items.add(Items("CoffeTable", "brown"));
But then got the error while creating create method 'Items(String,String)'
You can simple create the new item in the call of add:
items.add(new Item("CoffeTable", "brown"));
So you don't need an explicit variable.
Also note that in Java variable names normally start with a lower case character.
You will have to create a new object anyway to hold these 2 values.
You can do this:
Items.add(new Item("CoffeTable", "brown"));
Anything else you come up with will be syntactic sugar for the above
For example: you can add a static method to your class:
public static Item item(String k1, String k2) {
return new Item(k1, k2);
}
And use it later:
Items.add(item("CoffeTable", "Brown"));
Here is a solution which would surely work. You can add a function to your class itemAdd() as follows:
class Samp {
public static void main(String args[]){
//code.....
ArrayDeque<Item> Items= new ArrayDeque<Item>();
Items.add(itemAdd("CoffeeTable", "brown"));
//rest of code....
}
public static Item itemAdd(String tableType,String colourOfTable){
return new Item(tableType,colourOfTable);
}
}
class Item{
String tableType;
String colourOfTable;
Item(String tableType,String colourOfTable ){
this.tableType=tableType;
this.colourOfTable=colourOfTable;
}
}
Its similar to what u need to do!! Best of luck :)

Array of type Object, and comparing the objects inside the array

I am creating an array of type Object. I have two different classes, Employee and Person which have simple attributes like name, salary (Employee) first name, date of birth (Person). I need to add some Employee and Person objects into my array and compare certain things within the array. Ex, retrieving the youngest Person from the array.
public class Driver {
public static void main(String[] args) {
Employee e1 = new Employee("Den", 2000);
Employee e2 = new Employee("Jon", 1004);
Person p1 = new Person("Pen", "Tel", "1993");
Person p2 = new Person("Jon", "Smith", "1933");
Object [] crr;
crr = new Object[4];
crr[0] = e1;
crr[1] = p1;
crr[2] = p2;
crr[3] = e2;
System.out.println();
new Driver().printObjectArray("array crr", crr);
}
public void printObjectArray(String arrayName, Object [] array){
for (int i = 0; i < array.length; i++){
System.out.println(arrayName + "["+ i +"]" + array[i].toString());
}
System.out.println("--------------------");
}
}
How would I compare certain things on the array. Like printing the youngest person,, which means I have to look through the array and see if its a Person object then getDateOfBirth on those objects and print the oldest person.
public Person getYoungestPerson(Object [] arr){
int i=0; Person youngest;
while(person == null){
if(arr[i] instanceof Person) youngest = arr[i];
i++;
}
for(i=0;i<arr.length;i++){ if (arr[i] instanceof Person)
if(arr[i].getDateOfBirth()<youngest.getDateOfBirth())
youngest= arr[i];}
return youngest;
}
Ideally, Employee should be a child class from Person, and you would have a Person array. You have to be careful if you want only Persons, because instanceofalso returns true for all child classes, this is not your case, because Employee does not extends Person, just a heads up to the future.
Write some get methods in your Employee and Person classes. For example,
in your Employee class, create:
public int getSalary(){
return salary; // Make salary as a global variable
}
In your Person class, do
public int getYear(){
return year; // same here
}
So in you main code, you can do
for (int i = 1; i < array.length; i++){
Object youngest;
if (crr[i].getYear() < crr[i+1].getYear())){
youngest = crr[i];
}
}
However, I actually would like to recommend you to use ArrayList instead of array. And Creat two arrays/ArrayLists instead of putting e and p in one array. Easier to manage.
Don't use arrays of type Object. Java excels at strong typing, so take advantage of that. If Person extends Employee, or Employee extends Person, exploit that. Initialise your array with the top class:
Person[] people = {new Employee(...), new Employee(...),
new Person(...), new Person(...)};
or
Person[] people;
...
people = new People[]{new Employee(...),
new Employee(...), new Person(...), new Person(...)};
or
Person[] people = new People[<some number>];
...
people[0] = new Employee(...);
people[1] = new Person(...);
...
And then we can sort the array by making sure Person (or Employee) implements Comparable (or Employee), implementing compareTo(Person other) {...} (or Employee), and calling Arrays.sort(people). Because we made them comparable, Java will know how to sort them.
There's a lot of things Java can do for you, but you'll have to play by its rules. Not using "Object" containers is one of them, implementing the Comparable interface is another (a third one is to use generics on containers like ArrayList, HashMap, etc, so that Java knows what you're putting in them, rather than the catch-all "Object")
If Person isn't "related" to Employee through extension you could force both classes to implement the same interface. Create and array of that interface type and put Employee and Person objects into it. Then use the interface methods to compare Employee and Person objects.
I think the best option here is to have Employee extend Person, but interfaces can provide a nice alternative.

Categories

Resources