I made this Student ArrayList that have name, age and number variable. I manually input 3 student. I want to check if a name already exist in my list. I tried to use list.contains but it seems not working. Are there certain way to do for this kind of ArrayList?
public class CompareToeX {
public static void main(String[] args) {
ArrayList<Student> obj=new ArrayList<Student>();
obj.add(new Student("Peter", 27,1));
obj.add(new Student("John",26,7));
obj.add(new Student("Jack",21,5));
if(obj.contains("Peter")){
System.out.println("Peter on is on the list!");
} else {
System.out.println("Peter is not on the list!");
}
}
}
This is the Student class
public class Student{
private String studentName;
private int age;
private int rollno;
public Student(String studentName, int age, int rollno){
this.studentName=studentName;
this.age=age;
this.rollno=rollno;
}
public String getStudent(){
return studentName;
}
public int getAge(){
return age;
}
public int getRollno(){
return rollno;
}
public void setStudent(String Student){
studentName=Student;
}
public void setAge(int age){
this.age=age;
}
public void setRollno(int rollno){
this.rollno=rollno;
}
}
After I run, the result should show that peter is on the list right. But it goes the other way around. It seems that the contains method is not working.
A student isn't a name.
.contains() will fail here because the string "Peter" is not in the list. It obviously isn't; how could it be? This list only contains Student objects, not Strings, after all.
You'll have to write a for loop, or use streams.
boolean peterIsInTheList = false;
for (var s : students) {
if (s.getName().equals("peter")) peterIsInTheList = true;
}
or
boolean peterIsInTheList = students.stream()
.anyMatch(s -> s.getName().equals("peter"));
Alternatively you could use the idea of a map; change your data structure. Instead of using a list, have a map that maps first names onto student objects:
Map<String, Student> students = new HashMap<>();
students.put("peter", new Student(....));
if (students.containsKey("peter")) {
// peter is in the list
}
You are checking if the String Peter is in the list, or the list only contains Student object. So you can only check if Student is contained inside the list (be sure to implement the right equals/hashcode method if you wish to use .contains).
This will do
obj.stream()
.filter(student -> student.getStudent().contains("Peter"))
.findFirst()
.ifPresentOrElse(student -> System.out.println("Peter on is on the list!"), () -> System.out.println("Peter is not on the list!"));
Being not a default data type, I think you need to override some functions of ArrayList first, like the .compare() one.
It was answered here too
Java: to use contains in a ArrayList full of custom object should I override equals or implement Comparable/Comparator?
Related
Immutable Class with List
package com.text.immutable;
import java.util.Collections;
import java.util.List;
// An immutable class Student
public final class Student
{
final String name;
final int regNo;
final List<String> courses; // want to make Immutable
public Student(String name, int regNo, List<String> courses)
{
this.name = name;
this.regNo = regNo;
this.courses = Collections.unmodifiableList(courses);
}
public String getName()
{
return name;
}
public int getRegNo()
{
return regNo;
}
public List<String> getCourses() {
return courses;
}
}
Testing Immutable Class to Break Immutability
package com.text.immutable;
import java.util.ArrayList;
import java.util.List;
class ImmutablityTest
{
public static void main(String args[])
{
List<String> courses = new ArrayList<String>();
courses.add("java");
courses.add("spring");
courses.add("hibernate");
courses.add("rest");
Student s = new Student("ABC", 101, courses);
System.out.println("Before Update List");
System.out.println(s.getName());
System.out.println(s.getRegNo());
System.out.println(s.getCourses());
courses.add("Hibernate"); // Able to Change which affect final OutCome
//s.getCourses().add("SpringBoot"); // giving Exception in thread "main" java.lang.UnsupportedOperationException
System.out.println("After Update List");
System.out.println(s.getName());
System.out.println(s.getRegNo());
System.out.println(s.getCourses());
}
}
Output is
Before Update List
ABC
101
[java, spring, hibernate, rest]
After Update List
ABC
101
[java, spring, hibernate, rest, Hibernate]
why and how this new Course element added into the List as its from Client Side can be added up any time so how we can fix this issue as this immutable class should not allow to modifying after once created
this.courses = Collections.unmodifiableList(courses);
That creates, as the name says, an unmodifiable list. But that is just a view on the original list. Thus changes to that original list become visible in your "unmodifiable" view.
When in doubt: clone your list, like:
this.courses = new ArrayList<>(courses);
And then ensure that your getter does:
return Collections.unmodifiableList(courses);
Not the best in context of memory, but works:
// An immutable class Student
public final class Student
{
final String name;
final int regNo;
final List<String> courses; // want to make Immutable
public Student(String name, int regNo, List<String> courses)
{
this.name = name;
this.regNo = regNo;
this.courses = new ArrayList(courses);
}
public String getName()
{
return name;
}
public int getRegNo()
{
return regNo;
}
public List<String> getCourses() {
return new ArrayList(courses);
}
}
On input (in constructor) you create copy of list and on output (in getter) you create copy.
read about immutableLists and you'll find that an Immutable and Unmodifiable Are Not the Same.
I guess (from your question) you are expecting an unmodifiable list which you simply don't create...
see this answer for a proper solution
With Collections.unmodifiableList, it creates a wrapper around the original list and that wrapper object is unmodifiable. The original list can still be updated.
So, in order for the List<String> courses list to be immutable, you can use Apache collection common library.
List<String> immutableList =
com.google.common.collect.ImmutableList.of("Geeks", "For","Geeks");
ImmutableList has overridden the List.add method to always throw exception java.lang.UnsupportedOperationException
Second alternative is to create the list inside the constructor itself.
public Student(String name, int regNo, String... args)
{
this.name = name;
this.regNo = regNo;
courses = (List)Arrays.asList(args);
}
And call it like this :
Student s = new Student("ABC", 101, "a","a","a","a");
This question already has answers here:
How to sort List of objects by some property
(17 answers)
Closed 3 years ago.
In this program I sorted strings in Alphabetic way in Simple Array but how can I do the same thing using List or ArrayList, Suppose I have a class Students and I want to order names in an alphabetically way, so how can I do that?
public class CityData{
public static String citynames[]= {"Hyderabad","Karachi","Abtabad","AzadKashmir"};
public static void main(String args[]) {
int size=citynames.length;
String temp=null;
for(int i=0; i<size; i++) {
for(int j=i+1; j<size; j++) {
if(citynames[i].compareTo(citynames[j])>0) {
temp=citynames[i];
citynames[i]=citynames[j];
citynames[j]=temp; }
}
System.out.println(citynames[i]);
}
}
}
Result:
Abtabad
AzadKashmir
Hyderabad
Karachi
You can sort the collections based on your requirements.
If the input objects for collections is implementing the Comparable interface like String, Integer, Double classes, then you can directly use Collections.sort() method from Collections util class
List<String> al = new ArrayList<>();
al.add("Hyderabad");
al.add("Karachi");
al.add("Abtabad");
al.add("AzadKashmir");
al.add("Udupi");
al.add("Jammu");
Collections.sort(al);
Or you can sort the list based on your requirement.(Reverse alphabetical Order)
Collections.sort(al, (str1, str2) -> str2.compareTo(str1));
If you don't want to use the Collections class, then directly use the sort() method present in List interface.
i. Albhabetical Order
al.sort((str1, str2) -> str1.compareTo(str1));
ii. Reverse Albhabetical Order
al.sort((str1, str2) -> str2.compareTo(str1));
The above solution is for the Objects where the class implements the Comparable Interface like String, Integer, Double, etc...
When to sort the Custom Classes, you need to implement sort by Comparator class or Lambda expression for the Comparator.
Consider you have a Student Class, and need to sort by city names. You can use below code.
Student Class
public class Student {
private String name;
private String city;
public Student() {}
public Student(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
#Override
public String toString() {
return "Student -> [name=" + name + ", city=" + city + "]";
}
}
Sorting By Collection Class sort() method
Student st1 = new Student("Samir", "Hyderabad");
Student st2 = new Student("Akbar", "Karachi");
Student st3 = new Student("Ramu", "Abtabad");
Student st4 = new Student("Rahim", "AzadKashmir");
Student st5 = new Student("Sardar", "Udupi");
Student st6 = new Student("Fahad khan", "Jammu");
List<Student> al2 = new ArrayList<>();
al2.add(st1);
al2.add(st2);
al2.add(st3);
al2.add(st4);
al2.add(st5);
al2.add(st6);
//Alphabetical Order
Collections.sort(al2, (std1, std2) -> std1.getCity().compareTo(std2.getCity()));
//Reverse Alphabetical Order
Collections.sort(al2, (std1, std2) -> std2.getCity().compareTo(std1.getCity()));
By using List.sort() method
//Alphabetical Order
al2.sort((std1, std2) -> std1.getCity().compareTo(std2.getCity()));
//Reverse Alphabetical Order
al2.sort((std1, std2) -> std1.getCity().compareTo(std2.getCity()));
What you are looking for is actually pretty simple to do:
Instead of using citynames[i] or citynames[j], for Lists and ArrayLists, you use citynames.get(i) or citynames.get(j).
Just think of List.get() is the same as the brackets you put before for the simple arrays.
Just remember, when you want to set a value, you actually have to use the List.set(int index, Object value).
The same can be said if you are trying to get the length of the List or ArrayList. You can simply replace citynames.length to citynames.size();
public static void main(String args[]) {
int size=citynames.size();
String temp=null;
for(int i=0; i<size; i++) {
for(int j=i+1; j<size; j++) {
if(citynames.get(i).compareTo(citynames.get(j))>0) {
temp=citynames.get(i);
citynames.set(i, citynames.get(j));
citynames.set(j, temp); }
}
System.out.println(citynames.get(i));
}
}
Update: Better Solution:
Note: When using Collections.sort() it is important to make sure the object type of the array implements Comparable. the Collections.sort() uses the compareTo() within the object class to sort the elements.
public class Main(){
import java.util.Collections;
public static void main(String args[]) {
ArrayList<City> citynames = new ArrayList<City>();
citynames.add("Hyderabad");
citynames.add("Karachi");
citynames.add("Abtabad");
citynames.add("AzadKashmir");
Collections.sort(citynames);
for(cityname : citynames)
System.out.println(cityname);
}
}
public class City implements Comparable{
private String name;
// Constructor
public City(String name){
this.name = name;
}
// Getter method
public String getName(){
return name;
}
// compareTo Method
public int compareTo(City other){
return name.compareTo(other.getName());
}
// Other methods may exist
}
For more information: https://docs.oracle.com/javase/tutorial/collections/interfaces/order.html
I do not have the rights to comment yet, hence adding at as an answer.
You can google this easily and also lookup API for sorting collections.
Code in java 8
public class ArrayListSort {
public static String citynames[] = { "Hyderabad", "Karachi", "Abtabad", "AzadKashmir" };
public static void main(String args[]) {
Student stud1 = new Student("Alex", 20);
Student stud2 = new Student("Bryan", 21);
Student stud3 = new Student("Chris", 22);
Student stud4 = new Student("Dan", 23);
List<Student> students = new ArrayList<>(Arrays.asList(stud4, stud3, stud2, stud1));
Collections.sort(students);
for(Student stud: students){
System.out.println(stud.getName());
}
}
}
class Student implements Comparable<Student> {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return age;
}
#Override
public int compareTo(Student other) {
return this.name.compareTo(other.name);
}
}
Edit 1 to answer your comment, look up Comparable interface
we have
class Student
{
String name,
int age,
String specialization
}
and
class Students
{
List<String> names,
List<Integer> age,
List<String> specialization
}
Students object is basically a structure that holds field values of Student class,
What is the best way to fill Students object without using reflection.
Edit: we have a specific requirement of having Students class as it is, the reason for this is we don't always want all the information in Student class and if we have List it would allocate memory for the fields that we are not interested in.
Don't create class Students. Hold a list of Student
List<Student> students = new ArrayList<Student>();
And to access a student data you can use
students.get(0).name;
As a side note, you should learn about getters and setters.
I wouldn't recommend creating a class named "Students" for this purpose. Your intention is to create a collection to hold the Student objects.
In this case, do the following:
List<Student> students = new ArrayList();
Also, pay attention to the capitalization: class is a keyword and should be spelled all lower-case.
EDIT After seeing a comment from venkat:
If you really need to create a class called Students then following should work (also similar answer provided above by another SO user):
class Students {
List<Student> students = new ArrayList();
}
This should work, but I would highly recommend not to use these type of class with the plural names!
PS: I am a CS prof teaching programming languages in a university and a long time developer/consultant.
Class Students {
List<Student> students;
}
Maybe you want to use a Decorator-Pattern (I don't think that i saves memory):
Implement a base class with the default field:
public class BaseClass implements INameGettable {
protected String name;
public BaseClass(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Add the default interface:
public interface INameGettable {
String getName();
}
Add a decorator to for an additional field e.g. age:
public class Decorator implements INameGettable {
protected INameGettable nameable;
protected int age;
public Decorator(INameGettable nameable, int age) {
this.nameable = nameable;
this.age = age;
}
public String getName() {
return nameable.getName();
}
public int getAge() {
return this.age;
}
}
Usage:
// First object contains only name
INameable namegettable = new BaseClass("Test1");
namegettable.getName();
// Second object contains name and age
Decorator agegettable = new Decorator(new BaseClass("Test2"), 77);
agegettable.getName();
agegettable.getAge();
Going for the obvious answer here.
class Students
{
List<String> names;
List<Integer> age;
List<String> specialization;
public Student(List<Student> students) {
addStudents(students);
}
private void addStudents(List<Student> students) {
names = students.stream
.map(Student::getName)
.collect(Collectors.toList())
age = students.stream
.map(Student::getAge)
.collect(Collectors.toList())
specialization = students.stream
.map(Student::getSpecialization)
.collect(Collectors.toList())
}
}
I am having my final exam tomorrow so i am practicing some questions.But i am stuck at this question.I am given a person class file and a half completed quiz10 file whereby i have to fill up.The quiz10 codes are halfway done(given).
I need to implement a function findPersonWhoseNameStartWith which returns the names of the persons in the list who start with A. But i have no idea how.
Output wanted:
result:April,Adam
public class Person{
private int age;
private String name;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public int getAge(){
return age;
}
public String getName(){
return name;
}
public String toString(){
return "" + name;
}
}
Half given codes(I have indicate which part i have attempted):
import java.util.*;
public class Quiz10{
public static void main(String[] args){
ArrayList<Person>list=new ArrayList<Person>();
list.add(new Person("April",9));
list.add(new Person("Adam",3));
list.add(new Person("bil",9));
list.add(new Person("cpril",9));
list.add(new Person("dpril",9));
ArrayList<Person>result=findPersonWhoseNameStartWith(list,"A");
System.out.println("result:");
//START DOING FROM HERE
for(int i=0;i<list.size();i++){
Person p=list.get(i);
if(p.findPersonWhoseNameStartWith("A");
}
}
You are on the right track. you are right you have to iterate over the list. Now for each entry output it if it starts with 'A'. It's very simple and a single if statement way easier than what you imagine it seems.
// pass your personList and the prefix, return a list of person starting with the prefix you specified
private List<Person> findPersonWhoseNameStartWith(List<Person> personList, String prefix) {
// create a list to store your result
List<Person> matchedList = new ArrayList<Person>();
// TODO iterate personList
// add them to the matchedList if the prefix matches
return matchedList;
}
public List<Person> findAPersonWhoStartsWith(List<Person> persons, String aLetter){
List<String> personsNames = new ArrayList<String>();
if(persons!=null && aLetter!=null && !aLetter.isEmpty()){
for(Person aPerson:persons){
if(aPerson.getName().startsWith(aLetter)){
personsNames.add(aPerson);
}
}
}
return personsNames;
}
in my program there are three class Student,School and TestStudent. I have declared students state inside student class and also there are methods for getting students subject,i have created an array list of type student in School class,but when i try to access student's method in school i get error newStudent type can not be resolved.Here are my codes.
public class Student {
String name;
String subject;
int age;
Student(String name,String subject,int age){
this.name = name;
this.subject = subject;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public String getSubject(){
return this.subject;
}
public int getAge(){
return this.age;
}
}
public class School {
public ArrayList <Student> students = new ArrayList <Student>();
public void addStudent(String name,String subject,int age){
Student newStudent = new Student(name,subject,age);
students.add(newStudent);
}
public void showSubject(String student){
newStudent.getSubject();
}
}
newStudent.getSubject();
This is not what you want. Because you haven't retrieved that student yet from the ArrayList.
You would need to iterate over the ArrayList, and see which student have the name as passed in parameter.
So, just use a for-each loop to iterate over your ArrayList, and return appropriate Student.
So, your method should look like: -
public void showSubject(String student){
for (Student student: students) {
if (student.getName().equals(student)) {
System.out.println(student.getSubject());
}
}
}
Note that, using a Map here would be a better idea as explained by #Peter in his answer.
If you want to look up a student by name, I would make the name of a student immutable and use a Map<String, Student> instead. This would allow you to write
Student student = map.get(studentName);
Using a List, you would have to search through every entry as Rohit suggests. Note: it is possible to have multiple students with the same name (as in real life) with a List.
newStudent is a local variable in addStudent(), hence you cannot access it from showSubject().
I don't know what should be your logic of accessing the subject, but, for example, it could be accessed via students.get(0).getSubject() [provided the list is not empty]