I need to determine if a element in my ArrayList has a specific value. This is the current way I am trying.
public static boolean hasDwgNamedReference(Object valueDWG){
boolean b = false;
String dwgName = "dwg_";
if(valueDWG == null){
b = false;
}
else {
String checkNamedRef = Arrays.toString((Object[]) valueDWG).substring(1, 5);
System.out.println("checkNamedRef " + checkNamedRef + "\n");
if(checkNamedRef.equals(dwgName)){
b = true;
}
}
return b;
}// end hasDwgNamedReference
I am pretty sure that the issue is with the
String checkNamedRef = Arrays.toString((Object[]) valueDWG).substring(1, 5);
Do you think I need to increment the ArrayList and check each element?
Well, firstly, you do not need to include the first "if" statement. b is already false, so setting it to false again is unnecessary.
If you use the Arrays.toString() method on an object, you may get the identity of the object, or the address in memory that it holds. If you try to compare to checkNamedRef via an equals method, you may be comparing an address and a string, which would never give you the true you are looking for.
Related
I am using Ncalc to evaluate the presence of some string values
if (#Xval = 'Z','T','F')
this works well when #xval is inputted as a parameter as a single value(#Xval = 'Z'). That will return a true evaluation. I am now looking to evaluate the same formula when #Xval may be say 'Z','H' in other words Xval contains those 2 values and Im trying to find if 'Z' is among them.
The same goes for if (in (#Xval,'Z','H','M'),'T','F') where Im looking for the value of Xval in a group of options (Z,H,M).
Can I do this via custom functions? If so how? Any other ideas?
Thank you
You can try
Expression e = new Expression("if (iscontians("ZHM",#Xval),'T','F')", EvaluateOptions.IgnoreCase);
e.EvaluateFunction += evalFunction;
Write a custom function
private void evalFunction(string name, FunctionArgs args)
{
switch (name.ToUpper())
{
case "ISCONTAINS":
if (args.Parameters.Length < 2)
throw new ArgumentException("isContains() takes at least 2 arguments");
args.Result = args.Parameters[0].Evaluate().ToString().Contains(args.Parameters[1].Evaluate().ToString());
break;
default:
break;
}
}
So I have an arraylist basket that stores items, each item is made out of the name of the item and the price of the item fields.
As you can see there's two sugar with same price.
I want my code to print every single item with the amount of time its repeated.
What I want it to do is this:
Count the duplicate values
2 x Sugar for 100
1 x Cake for 75
1 x Salt for 30
1 x Fanta for 50
My Item class toString's method is
public String toString(){
return name + " for " + price;
}
basket = new ArrayList<Item>();
basket.add(new Item("Sugar", 100));
basket.add(new Item("Sugar", 100));
basket.add(new Item("Cake", 75));
basket.add(new Item("Salt", 30));
basket.add(new Item("Fanta", 50));
HashSet<Item> set = new Hashset(basket)
for (Item item : set ){
System.out.println(Collections.frequency(basket, item) + " x" + item);
}
But what it does is...
1 x Sugar for 100
1 x Sugar for 100
1 x Cake for 75
1 x Salt for 30
1 x Fanta for 50
so i'm thinking that its comparing the toStrings but the repeated ones are not equalling to true.
please help.
This is my first ever post and don't really know the exact rules of posting
It would be better to use a Map in this scenario. First, make sure you are implementing the equals(Object) and hashCode() methods in your Item object, then putting each unique Item into the map with a value of an AtomicInteger with base value 1. Before putting in the object in the map you should check to make sure the item is not already in the map, if it already exists in the map, get the AtomicInteger and increment it.
Something like this..
Map<Item, AtomicInteger> quantitiesByItem = new HashMap<>();
for (Item item : listOfItems) {
if (!quantitiesByItem.contains(item)) {
quantitiesByItem.put(item, new AtomicInteger(1));
} else {
quantitiesByItem.get(item).incrementAndGet();
}
}
A HashSet actually prevents duplicates so would only be useful in a scenario where you are trying to strip duplicate records.
EDIT: You could also use Collections.frequency but you need to implement equals(Object) and hashCode() in your Item object otherwise the objects are determined to be different because they aren't the exact same object. You will also need to stop adding all your values from your list to a set and instead just pass your List object to Collections.frequency method.
This is what my code was missing in my Item class;
You need to override the equals and hashcode methods that every objects have by default. This will allow you to compare two objects by their state.
object A with to private fields e.g. int field and a String field
with object B. If both fields are the same there return value will be true
#Override
public boolean equals(Object obj){
//check for null
if(this == null){
return false;
}
//make sure obj is a item
if(getClass() != obj.getClass()){
return false;
}
//cast obj as an item
final Item passsedItem = (Item) obj;
//check fields
if(!Objects.equals(this.name, passsedItem.name)){
return false;
}
if(!Objects.equals(this.price, passsedItem.price)){
return false;
}
return true;
}
/**
* Override hashcode method to be able to compare item state to see if they are the same
* #return
*/
#Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hashCode(this.price);
return hash;
}
I am currently using a sql data reader (in vb.net) to extract an article object via a stored proc from a SQL Server 2008 database. Part of this object includes the two properties shown below:
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))
theArticle.Relevance = ((myReader.GetInt32(myReader.GetOrdinal("Relevance"))))
My problem is that the Truthfulness and Relevance may return a null value and this is causing the function to fall over.
I think I understand why. I am asking for an integer value (getin32) and because null is returned it fails.
How do I accommodate the null value from the database so it does not fall over?
You can check whether or not a given ordinal position is null using .IsDBNull() and then do something - e.g. set your value to -1 or something:
int myOrdinal = myReader.GetOrdinal("Truthfullness");
if(myReader.IsDBNull(myOrdinal))
{
theArticle.Truthfulness = -1;
}
else
{
theArticle.Truthfulness = myReader.GetInt32(myOrdinal);
}
As Mike Hofer points out in his answer, you could also wrap all this logic into an extension method:
public static class SqlDataReaderExtensions
{
public static int SafeGetInt32(this SqlDataReader reader,
string columnName, int defaultValue)
{
int ordinal = reader.GetOrdinal(columnName);
if(!reader.IsDbNull(ordinal))
{
return reader.GetInt32(ordinal);
}
else
{
return defaultValue;
}
}
}
and then just use that "SafeGetInt32" method instead:
theArticle.Truthfulness = myReader.SafeGetInt32("Truthfullness", -1);
Marc
Did you check, SqlDataReader.IsDBNull Method? Probably something like:
if(myReader.IsDBNull(myReader.GetOrdinal("Truthfulness"))
theArticle.Truthfulness = string.Empty;
else
theArticle.Truthfulness = ((myReader.GetInt32(myReader.GetOrdinal("Truthfulness"))))
You know, I deal with this all the time in Oracle. To clean the code up, I wrote a set of extension methods to simplify the operation:
using System.Data.OracleClient;
public static class OracleDataReaderExtensions
{
public static int GetInt32(this OracleDataReader reader, string columnName, int defaultValue)
{
return reader.GetInt32(reader.GetOrdinal(columnName)) != DbNull.Value ?
reader.GetInt32(reader.GetOrdinal(columnName)) :
defaultValue;
}
}
Create a separate overload for each type you want to return. I primarily work with string, int, date, and decimal. Remember YAGNI (you don't need to work with every type supported by the reader, only those you actually use.)
An extension class like this for SQL Server is really easy to write, and will VASTLY simplify your work. Trust me on that. Would I lie to you? :)
This generic version may be of use:
private T ValueOrDefault<T>(System.Data.IDataReader rdr, string columnName)
{
T vod = default(T);
try
{
int idx = rdr.GetOrdinal(columnName);
if (!rdr.IsDBNull(idx))
return (T)rdr[idx];
}
catch (IndexOutOfRangeException) { }
return vod;
}
Could be extended to catch InvalidCastException, or use Convert.ChangeType instead of casting?
IsDbNull(int) is usually much slower that using methods like GetSqlInt32 and then comparing to DBNull.Value or using it's own .IsNull Like:
public static int Int32(this SqlDataReader r, int ord)
{
var t = r.GetSqlInt32(ord);
return t.IsNull ? default(int) : t.Value;
}
Tried a few template solutions but to no avail so far. The problem is that all Sql-types (SqlInt32 here) types are actually structs and while they all have .Value property C# doesn't have real templates to handle that. Also they have their own INullable interface which has only .IsNull and is not conpatible with Nyllable<>.
I suspect that one would need full set of Sql-types as C# templates or to add ICOnvertible to them in order to be able to have just one or two templated methods.
If someone has maybe an idea with a functional trick or two speak up :-)
Here is what we use on SQLServer and it works like a charm:
...
Dim X as Object = pbDr("TotAmt") 'dr is dim'ed as a DataReader
...
Public Function pbDr(ByVal drName As String) As Object
Dim SQLError As SqlClient.SqlException
Dim IsNull As Boolean
Dim Ordinal, DispNbr As Integer
Try
Ordinal = dr.GetOrdinal(drName)
IsNull = dr.IsDBNull(Ordinal)
If IsNull Then
Dim Dbtype As String = dr.GetFieldType(Ordinal).ToString
If Dbtype = "System.String" Then
Return ""
ElseIf Dbtype = "System.Int32" _
OrElse Dbtype = "System.Double" _
OrElse Dbtype = "System.Decimal" _
OrElse Dbtype = "System.Int16" Then
Return 0
Else
MsgBox("Print This Screen And Send To Support" _
& "pbdr-Object = " & Dbtype, MsgBoxStyle.Critical)
Return ""
End If
Else
Return dr(Ordinal)
End If
Catch sqlerror
Call DispSQLError(SQLError, "pbDr")
pbDr = ""
End Try
End Function
Nowadays, you probably want the null if the database returns it and as such you would use a Nullable<int>:
public static class Extensions
{
public static int? GetNullableInt32(this SqlDataReader reader, int ordinal)
{
if (reader.IsDBNull(ordinal))
return null;
return reader.GetInt32(ordinal);
}
public static long? GetNullableInt64(this SqlDataReader reader, int ordinal)
{
if (reader.IsDBNull(ordinal))
return null;
return reader.GetInt64(ordinal);
}
}
I'm trying to retrieve a list of orders based on parameters specified by a user (basic search functionality). The user will enter either an orderId or a bunch of other params, those will get wrapped up into a message, and eventually make their way to the method below. My question is, how do I only look at the parameters that actually have values? So if a user were to enter a received date range and a store number and all other fields were null, I want to return orders for stores received in the date range and ignore all the null parameters. At first I was thinking I could use a conjunction, but I can't see a way to ignore the null parameters. Then I started splitting things out into the if statements below the main expression, but I don't want to look at those criteria if the user provides an externalId. Is there a simple way to do this?
public IList<Core.Order> GetOrderByCriteria
(
string ExternalId,
int? Store,
int? Status,
DateTime? beforeTransmissionDate, DateTime? afterTransmissionDate,
DateTime? beforeAllocationProcessDate, DateTime? afterAllocationProcessDate,
DateTime? beforeReceivedDate, DateTime? afterReceivedDate
)
{
try
{
NHibernate.ICriteria criteria = NHibernateSession.CreateCriteria(typeof(Core.Order))
.Add(Expression.Or
(
Expression.Like("ExternalId", ExternalId),
Expression.Conjunction()
.Add(Expression.Between("ReceivedDate", beforeReceivedDate, afterReceivedDate))
.Add(Expression.Between("TransmissionDate", beforeTransmissionDate, afterTransmissionDate))
.Add(Expression.Between("AllocationProcessDate", beforeAllocationProcessDate, afterAllocationProcessDate))
)
);
if(Store.HasValue)
criteria.Add(Expression.Eq("Status", Status));
if(Status.HasValue)
criteria.Add(Expression.Eq("Store", Store));
return criteria.List<Core.Order>();
}
catch (NHibernate.HibernateException he)
{
DataAccessException dae = new DataAccessException("NHibernate Exception", he);
throw dae;
}
}
I wound up dropping the whole conjunction thing and replacing the code in the try block with the code below. I also used joins which reduced the number of db accesses and reduced the amount of code needed.
NHibernate.ICriteria criteria = NHibernateSession.CreateCriteria(typeof(Core.Order));
if (!String.IsNullOrEmpty(ExternalId))
{
criteria.Add(Expression.Like("ExternalId", ExternalId));
}
if (beforeReceivedDate != null && afterReceivedDate != null)
criteria.Add(Expression.Between("ReceivedDate", beforeReceivedDate, afterReceivedDate));
if (beforeTransmissionDate != null && afterTransmissionDate != null)
criteria.Add(Expression.Between("TransmissionDate", beforeTransmissionDate, afterTransmissionDate));
if (beforeAllocationProcessDate != null && afterAllocationProcessDate != null)
criteria.Add(Expression.Between("AllocationProcessDate", beforeAllocationProcessDate, afterAllocationProcessDate));
if (Store.HasValue)
criteria.CreateCriteria("Store", "Store").Add(Expression.Eq("Store.LocationNumber", Store.Value));
return criteria.List<Core.Order>();
I had to do something similar not long ago. I'm pretty sure you can modify this to fit your needs.
private ICriteria AddSearchCriteria(ICriteria criteria, string fieldName, string value)
{
if (string.IsNullOrEmpty(fieldName))
return criteria;
if(string.IsNullOrEmpty(value))
return criteria;
criteria.Add(Expression.Like(fieldName, "%" + value + "%"));
return criteria;
}
The code calling the method ended up looking like this:
var query = session.CreateCriteria(typeof (User));
AddSearchCriteria(query, "FirstName", form["FirstName"]);
AddSearchCriteria(query, "LastName", form["LastName"]);
var resultList = new List<User>();
query.List(resultList);
return resultList;
Leave it up to the function to determine if the input is valid and whether to return the unmodified ICriteria or to add another Expression before returning it.
I have a list:
Dim list As New List(Of String)
with the following items:
290-7-11
1255-7-12
222-7-11
290-7-13
What's an easy and fast way to search if duplicate of "first block" plus "-" plus "second block" is already in the list. Example the item 290-7 appears twice, 290-7-11 and 290-7-13.
I am using .net 2.0
If you only want to know if there are duplicates but don't care what they are...
The easiest way (assuming exactly two dashes).
Boolean hasDuplicatePrefixes = list
.GroupBy(i => i.Substring(0, i.LastIndexOf('-')))
.Any(g => g.Count() > 1)
The fastest way (at least for large sets of strings).
HashSet<String> hashSet = new HashSet<String>();
Boolean hasDuplicatePrefixes = false;
foreach (String item in list)
{
String prefix = item.Substring(0, item.LastIndexOf('-'));
if (hashSet.Contains(prefix))
{
hasDuplicatePrefixes = true;
break;
}
else
{
hashSet.Add(prefix);
}
}
If there are cases with more than two dashes, use the following. This will still fail with a single dash.
String prefix = item.Substring(0, item.IndexOf('-', item.IndexOf('-') + 1));
In .NET 2.0 use Dictionary<TKey, TValue> instead of HashSet<T>.
Dictionary<String, Boolean> dictionary= new Dictionary<String, Boolean>();
Boolean hasDuplicatePrefixes = false;
foreach (String item in list)
{
String prefix = item.Substring(0, item.LastIndexOf('-'));
if (dictionary.ContainsKey(prefix))
{
hasDuplicatePrefixes = true;
break;
}
else
{
dictionary.Add(prefix, true);
}
}
If you don't care about readability and speed, use an array instead of a list, and you are a real fan of regular expressions, you can do the following, too.
Boolean hasDuplicatePrefixes = Regex.IsMatch(
String.Join("#", list), #".*(?:^|#)([0-9]+-[0-9]+-).*#\1");
Do you want to stop user from adding it?
If so, a HashTable with the key as first block-second block could be of use.
If not, LINQ is the way to go.
But, it will have to traverse the list to check.
How big can this list be?
EDIT: I don't know if HashTable has generic version.
You could also use SortedDictionary which can take generic arguments.
If you're list contains only strings, then you can simply make a method that takes the string you want to find along with the list:
Boolean isStringDuplicated(String find, List<String> list)
{
if (list == null)
throw new System.ArgumentNullException("Given list is null.");
int count = 0;
foreach (String s in list)
{
if (s.Contains(find))
count += 1;
if (count == 2)
return true;
}
return false;
}
If you're numbers have a special significance in your program, don't be afraid to use a class to represent them instead of sticking with strings. Then you would have a place to write all the custom functionality you want for said numbers.