ignore fields while comparing two lists - collections

I have two lists of Person objects.
Person class has the below attributes
String Name,
Integer Age,
String Department,
Date CreatedTime,
String CreatedBy
When I compare my lists for equality, I would like not to compare the CreatedTime and CreatedBy fields.
How can I compare, using Java 8, the two lists for equality and also ignore the CreatedTime, CreatedBy fields for comparison?

You don't even need features from Java-8 to do this, simply override the equals & hashCode like this:
class Person {
String name;
Integer age;
String department;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
if (age != null ? !age.equals(person.age) : person.age != null) return false;
return department != null ? department.equals(person.department) : person.department == null;
}
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
result = 31 * result + (department != null ? department.hashCode() : 0);
return result;
}
}
Then you can compare two given lists like so:
boolean result = firstList.equals(secondList);
edit:
following your comment:
I need this form of comparison only for test purposeses . In my
production code I would like to retain equals and hashcode to compare
all fields
you can define a custom equal method like so:
public static boolean areEqual(List<Person> first, List<Person> second) {
Objects.requireNonNull(first, "first list must not be null");
Objects.requireNonNull(second, "second list must not be null");
return first.size() == second.size() &&
IntStream.range(0, first.size()).allMatch(index ->
customCompare(first.get(index), second.get(index)));
}
or if you want to allow null to be passed to the areEqual method then a little change will suffice:
public static boolean areEqual(List<Person> first, List<Person> second){
if (first == null && second == null)
return true;
if(first == null || second == null ||
first.size() != second.size()) return false;
return IntStream.range(0, first.size())
.allMatch(index ->
customCompare(first.get(index), second.get(index)));
}
then along with it the method that will determine if two given person objects are equal:
static boolean customCompare(Person firstPerson, Person secondPerson){
if (firstPerson == secondPerson) return true;
if (firstPerson.getName() != null
? !firstPerson.getName().equals(secondPerson.getName()) : secondPerson.getName() != null)
return false;
return (firstPerson.getAge() != null ? firstPerson.getAge().equals(secondPerson.getAge()) : secondPerson.getAge() == null)
&& (firstPerson.getDepartment() != null
? firstPerson.getDepartment().equals(secondPerson.getDepartment())
: secondPerson.getDepartment() == null);
}
Then call it like so:
boolean result = areEqual(firstList, secondList);

You can use Streams.zip() from Guava for a more functional solution. Ignoring null checks for brevity:
public static boolean comparePersonLists(List<Person> list1, List<Person> list2) {
if (list1.size() != list2.size()) {
return false;
}
return Streams.zip(list1.stream(), list2.stream(), (a, b) ->
a == b || (a.name.equals(b.name) && a.age.equals(b.age) && a.department.equals(b.department))
).allMatch(t -> t);
}

Related

Ceylon metamodel

I am studying Ceylon and have question about it metamodel. I want to create some create some base class 'DataContainer' which allow to instantiate immutable classes with build-in equals-hash implementation:
e.g. Identifier(125, "ab") == Identifier(125, "ab")
So base class should collect all shared non-variable values and use this information in 'hash' an 'equals' methods.
I have wrote this code:
shared abstract class DataContainer(ClassDeclaration declaration) {
value members = {
for (i in declaration.memberDeclarations<ValueDeclaration>())
if (!i.variable, i.name != "hash", i.name != "string") i
};
variable Integer? hashCode = null;
shared actual Boolean equals(Object that) {
if (is DataContainer that) {
for (item in members) {
value thisMember = item.memberGet(this);
value thatMember = item.memberGet(that);
if (exists thisMember, exists thatMember) {
if (thisMember != thatMember) { return false; }
} else if (thisMember exists != thatMember exists) { return false; }
}
return true;
}
return false;
}
shared actual Integer hash => hashCode else (hashCode = calculateHash());
Integer calculateHash() {
variable value result = 0;
for(i in members) {
if (exists member = i.memberGet(this)) {
result = result.xor(member.hash);
}
}
return result;
}
}
class Identifier(shared Integer? id, shared String? name) extends DataContainer(`class`) {}
The Identifier class is the client of DataContainer. I like this solution in whole but I have to pass 'class' into the super class constructor because if I use 'class' inside DataContainer it doesn't see any members of subclass.
How can I obtain actual list of extended class's members in base class methods?
Something like 'this' doesn't work...
I found solution thanks to guys from Ceylon community. The function classDeclaration(this) from ceylon.language.meta should be used instead of 'class'.
This is the final code:
shared abstract class DataContainer() {
variable Integer? _hash = null;
variable ValueDeclaration[]? _members = null;
shared actual Boolean equals(Object that) {
if (is DataContainer that) {
for (i in members) {
value thisMember = i.memberGet(this);
value thatMember = i.memberGet(that);
if (exists thisMember, exists thatMember) {
if (thisMember != thatMember) { return false; }
} else if (thisMember exists != thatMember exists) { return false; }
}
return true;
}
return false;
}
shared actual Integer hash => _hash else (_hash = calculateHash());
ValueDeclaration[] members => _members else (_members = [
for (i in classDeclaration(this).memberDeclarations<ValueDeclaration>())
if (!i.variable, i.name != "string", i.name != "hash") i
]);
Integer calculateHash() {
variable Integer result = 0;
for (i in members) {
if (exists member = i.memberGet(this)) {
result = result.xor(member.hash);
}
}
return result;
}
}
class Identifier(shared Integer? number, shared String? name) extends DataContainer() {}
Adding to Alexander's formidable answer, I took the liberty to implement a string function as well so you can just print(myObj) and it renders nicely:
shared default actual String string {
value s = StringBuilder();
s.append(type(this).declaration.name).append(" { ");
for (i in members) {
value m = i.memberGet(this);
s.append(i.name).append(":");
s.append(if(exists m) then m.string else "<null>");
}
return s.append(" }").string;
}

Detect blank HTML form input values

When I submit a HTML form with blank data it's still going into else block below:
String n=request.getParameter("uname");
String e=request.getParameter("mail");
String p=request.getParameter("pwd");
if(n==null || e==null || p==null)
{
// ...
} else
{
// ...
}
How can I make sure that it enters the if block?
Blank submitted input values do not arrive as null. Instead, they arrive as empty string. The null only means that the input value was not submitted at all (i.e. the input field was totally absent in the form).
If you're not interested in distinguishing the presence of a specific input field in the form, then add a String#isEmpty() check to the if block.
if (n == null || n.isEmpty() || e == null || e.isEmpty() || p == null || p.isEmpty()) {
// ...
}
You could even bake a custom utility method for this.
public static boolean isEmpty(String string) {
return (string == null || string.isEmpty());
}
if (isEmpty(n) || isEmpty(e) || isEmpty(p)) {
// ...
}
You can even go a refactoring step further with help of varargs.
public static boolean isOneEmpty(String... strings) {
for (String string : strings) {
if (string == null || string.isEmpty()) {
return true;
}
}
return false;
}
if (isOneEmpty(n, e, p)) {
// ...
}
If you would like to cover whitespace as well, then replace string.isEmpty() over all place by string.trim().isEmpty().
See also:
Our Servlets wiki page
How to determine which form has been submited and to validate them in a servlet
Validating numbers with Servlets and JSP
This is because uname,mail,pwd variables are not null instead these parameters contains empty strings.
i.e.
uname="";
mail="";
pwd="";
when you check whether these parameters are null or not , it results into false and your else block executes and persist the record into database.
you can create a method to check empty string(s).
public static boolean checkEmpty(String value){
if(!(value==null))
return value.isEmpty();
return true;
}
replace your if condition with this:
if(checkEmpty(n) || checkEmpty(e) || checkEmpty(p)){
}
String n=request.getParameter("uname");
if (n != null) n = n.trim();
if (n == null) n = "";
String e=request.getParameter("mail");
if(e != null) e = e.trim();
if(e == null) e = "";
String p=request.getParameter("pwd");
if(p != null) p = p.trim();
if(p == null) p = "";
//
// only process if values for all three exist
//
if((n.length() < 1) || (e.length() < 1) || (p.length() < 1))
{
// ...
} else
{
// ...
}

How to get just one value from querystrig

I'm write this function:
public static String QueryString(string queryStringKey)
{
if (HttpContext.Current.Request.QueryString[queryStringKey] != null)
{
if (HttpContext.Current.Request.QueryString[queryStringKey].ToString() != string.Empty)
return HttpContext.Current.Request.QueryString.GetValues(1).ToString();
}
return "NAQ";
}
And i want to get just one value from querystring parameter.
for example i send "page" to my function and url is: "sth.com/?page=1&page=2"
and function return to me: "1,2" ; but i want first value: "1", How?
GetValues returns a string[] if the key exists. An array is zero based, so you get the first element by using array[0], you are using GetValues(1) in your code, i assume that you wanted the first.
You could also use the Enumerable.First extension method:
Request.QueryString.GetValues("page").First();
Since GetValues returns not an empty array but null if the key was not present you need to check that explicitely (FirstOrDefault doesn't work):
public static String QueryString(string queryStringKey)
{
if (HttpContext.Current != null && HttpContext.Current.Request != null)
{
string[] values = HttpContext.Current.Request.QueryString.GetValues("queryStringKey");
if (values != null) return values.First();
}
return "NAQ";
}
A better approach would be -
public static String QueryString(string queryStringKey)
{
if (HttpContext.Current!=null && HttpContext.Current.Request!=null && !string.IsNullOrEmpty(HttpContext.Current.Request.QueryString[queryStringKey])
{
return HttpContext.Current.Request.QueryString.GetValues(queryStringKey).First();
}
return "NAQ";
}

C# check value exist in constant

I have declared my c# application constant this way:
public class Constant
public struct profession
{
public const string STUDENT = "Student";
public const string WORKING_PROFESSIONAL = "Working Professional";
public const string OTHERS = "Others";
}
public struct gender
{
public const string MALE = "M";
public const string FEMALE = "F";
}
}
My validation function:
public static bool isWithinAllowedSelection(string strValueToCheck, object constantClass)
{
//convert object to struct
//loop thru all const in struct
//if strValueToCheck matches any of the value in struct, return true
//end of loop
//return false
}
During runtime, I will like pass in the user inputted value and the struct to check if the value exist in the struct. The struct can be profession and gender. How can I achieve it?
Example:
if(!isWithinAllowedSelection(strInput,Constant.profession)){
response.write("invalid profession");
}
if(!isWithinAllowedSelection(strInput,Constant.gender)){
response.write("invalid gender");
}
You probably want to use enums, not structs with constants.
Enums gives you a lot of possibilities, it is not so hard to use its string values to save it to the database etc.
public enum Profession
{
Student,
WorkingProfessional,
Others
}
And now:
To check existence of value in Profession by value's name:
var result = Enum.IsDefined(typeof(Profession), "Retired"));
// result == false
To get value of an enum as a string:
var result = Enum.GetName(typeof(Profession), Profession.Student));
// result == "Student"
If you really can't avoid using value names with whitespaces or other special characters, you can use DescriptionAttribute:
public enum Profession
{
Student,
[Description("Working Professional")] WorkingProfessional,
[Description("All others...")] Others
}
And now, to get description from Profession value you can use this code (implemented here as an extension method):
public static string Description(this Enum e)
{
var members = e.GetType().GetMember(e.ToString());
if (members != null && members.Length != 0)
{
var attrs = members.First()
.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attrs != null && attrs.Length != 0)
return ((DescriptionAttribute) attrs.First()).Description;
}
return e.ToString();
}
This method fetches description defined in attribute and if there's none, returns value name. Usage:
var e = Profession.WorkingProfessional;
var result = e.Description();
// result == "Working Professional";

ASP.NET check if LinqToEntities returned something or not

How to make this method return boolean value, depending on query return. False - nothing, True - data exists. Before i just returned int from uniqueQuote.Count() but does not look like great method. Thank you!
private bool CheckEnquiryUser(int enquiryId, Guid userId)
{
int selectedEnquiryId = enquiryId;
Guid currentUserId = userId;
Entities ctx3 = new Entities();
var uniqueQuote = from quot in ctx3.Enquiries.Include("aspnet_Users")
where quot.EnquiryId == selectedEnquiryId &&
quot.aspnet_Users.UserId == currentUserId
select quot;
bool exist = uniqueQuote;
return exist;
Use the Enumerable.Any method:
return uniqueQuote.Any();
Or pass the predicate to it directly:
return ctx3.Enquiries.Include("aspnet_Users")
.Any(quot => quot.EnquiryId == selectedEnquiryId
&& quot.aspnet_Users.UserId == currentUserId);
I'm more used to this format, but you can translate to use .Any
return ctx3.Enquiries.Include("aspnet_Users")
.Any(x=> x.EnquiryId == selectedEnquiryId &&
x.aspnet_Users.UserId == currentUserId);
Try something like:
return uniqueQuote.Count() > 0;

Resources