Comparing two lists using LINQ - asp.net

If I have 2 lists of strings:
List<string> firstList = new List<string>("010", "111", "123");
List<string> secondList = new List<string>("010", "111", "999");
How can I compare each individual character in each item from the lists? Ex: Should compare "0" with "0", "1" with "1", "0" with "0" and so on. It appears that I can use SelectMany but I am stuck on how to do it
EDIT:
These lists should return true when compared with each other (as asterisk means any character and I am validating to ensure that each item is exactly 3 chars in length)
List<string> firstList = new List<string>("010", "111", "123");
List<string> secondList = new List<string>("010", "1*1", "***");

Updated with wildcards
class WildcardStringComparer : IEqualityComparer<string>
{
public bool Equals(string s1, string s2)
{
if (s1.Length != s2.Length) return false;
for (int i = 0; i < s1.Length; i++)
{
if (s1[i] != s2[i] && s1[i] != '*' && s2[i] != '*')
return false;
}
return true;
}
public int GetHashCode(string obj)
{
throw new NotImplementedException();
}
}
Results:
List<string> firstList = new List<string>{"010", "111", "999"};
List<string> secondList = new List<string>{"010", "111", "999"};
bool res = firstList.SequenceEqual(secondList, new WildcardStringComparer()); // True
and
List<string> firstList = new List<string>{"010", "111", "999"};
List<string> secondList = new List<string>{"010", "111", "*99"};
bool res = firstList.SequenceEqual(secondList, new WildcardStringComparer()); // True
and
List<string> firstList = new List<string>{"010", "111", "999"};
List<string> secondList = new List<string>{"010", "111", "199"};
bool res = firstList.SequenceEqual(secondList, new WildcardStringComparer()); // False

If you just want to compare for a matching character sequence between your lists:
bool sameCharacters = Enumerable.SequenceEqual(firstList.SelectMany(x => x),
secondList.SelectMany(x => x));
This would result in true, i.e. for the following two lists - their character sequences match ("010111123" for both), their individual string entries do not:
List<string> firstList = new List<string> {"010", "111", "123" };
List<string> secondList = new List<string> {"010", "11", "1123" };
Edit in response to comments:
For a wildcard match you could use Zip() and compare each character, return true if they match based on wildcard conditions, then just check that each element in the zipped sequence is true.
var isWildCardMatch = firstList.SelectMany(x => x).Zip(secondList.SelectMany( x => x),
(a,b) =>
{
if(a==b || a =='' || b == '')
return true;
return false;
}).All( x=> x);
Above approach crossed string entry boundaries, which would cause false matches - here a better approach:
bool isWildCardMatch = firstList.Zip(secondList, (x, y) =>
{
var matchWord = y.Select((c, i) => c == '*' ? x[i] : c);
return matchWord.SequenceEqual(x);
}).All(x => x);

Assuming you want to compare the first character of the first string in the first list to the first character of the first string of the second list, the second character of the first string in the first list to the second character of the first string in the second list, etc. I can think of two implementations.
The one I would start with:
var firstCharList = new List<char>();
var secondCharList = new List<char>();
firstList.foreach(s =>
{
foreach(char c in s)
{
firstCharList.Add(c);
}
});
secondList.foreach(s =>
{
foreach(char c in s)
{
secondCharList.Add(c);
}
});
for(int i = 0; i < firstCharList.Length; i++)
{
if(firstCharList[i] == secondCharList[i]) yield return i;
}
That would generate a list (or array, or whatever) of ints that correspond to indexes of which both strings had the same character.
The second would be something like:
firstList.foreach(s =>
{
var index = firstList.IndexOf(s);
var sPrime = secondList[index];
for(int i = 0; i < s.Length; i++)
{
if(s[i] == sPrime[i]) yield return s[i];
}
}
That one just returns any characters that are equal at the same indexes.

Related

Amazon DynamoDBv2 QueryOperationConfig SelectValues.Count not working

I have this piece of code like this:
var options = new DynamoDBOperationConfig
{
ConditionalOperator = ConditionalOperatorValues.Or,
OverrideTableName = nameTable,
ConsistentRead = true
};
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count
};
result = context.FromQueryAsync<TEntity>(queryConfig, options).GetRemainingAsync().Result;
as per the documentation, it should return just the count of values that match the filter, at least, the piece of code in the SelectValues class says that
//
// Summary:
// An enumeration of all supported Select values for Query and Scan. Value of Count
// will force service to return the number of items, not the items themselves.
but result is always an empty list; how can i make the count work ?
If you are still looking for the answer, this is the solution:
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count,
ConsistentRead = true
};
var table = context.GetTargetTable<TEntity>();
var search = table.Query(queryConfig);
result = search.Count;
Having ConsistentRead set to true will cause it to give you real time updates when the table is updated.
It's not working on Document level...
You can try to do this in low level model.
int count = 0;
Dictionary<string, AttributeValue> lastKey = null;
do
{
var request = new QueryRequest
{
TableName = "tableNmae",
IndexName = "indexName",
KeyConditionExpression = "ID= :v_ID",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{
":v_ID",
new AttributeValue
{
N = "1"
}
}
},
ConsistentRead = false,
Select = Select.COUNT,
ExclusiveStartKey = lastKey
};
var respone = await tableClient.QueryAsync(request);
count += respone.Count;
lastKey = respone.LastEvaluatedKey;
} while (lastKey != null && lastKey.Count != 0);

Join two dynamic Linq in Asp.net

I have used linq to store data, below is the code:
var result = (dynamic)null;
var serviceData = (dynamic)null;
var userData = (dynamic)null;
/****Linq 1*****/
serviceData= dtPasscode.AsEnumerable().Select(m => new
{
ACCOUNT_ID = intAccountId,
SUB_ACC_ID = m.Field<string>("ACCOUNT_ID_ALIAS")
});
/**Linq 2**/
userData = DisplyCustomerDetails(Convert.ToInt64(strSubAccountID));
result = serviceData.Concat(userData);
And another linq through function:
/**Function**/
System.Data.EnumerableRowCollection DisplyCustomerDetails(Int64 intAccountId)
{
var result = (dynamic)null;
/** Data Display if no service avaiable **/
IAccount_BL objAccount_BL = new Account_BL();
Customer objCustomer = new Customer();
DataTable dtCustomer = null;
int intErrorCount = 0;
objCustomer.Account_Id = Convert.ToInt64(intAccountId);
dtCustomer = objAccount_BL.GetCustomerDetails(objCustomer, ref intErrorCount);
objAccount_BL = null;
objCustomer = null;
if (intErrorCount == 0)
{
if (dtCustomer != null)
{
if (dtCustomer.Rows.Count > 0)
{
result = dtCustomer.AsEnumerable().Select(m => new
{
ACCOUNT_ID = intAccountId,
SUB_ACC_ID = m.Field<string>("ACCOUNT_ID_ALIAS")
});
}
}
}
return result;
}
I wanted to join both the result of Linq1 & Linq2, I tired Concat & Union, getting below error
'System.Data.EnumerableRowCollection<<>f__AnonymousTypea>' does not contain a definition for 'Concat'
To Concat both enumerables must of the same class; you cannot use anonymous classes. Define a class that has the two fields and change the code to Select them.
Also, don't use ... = (dynamic) null; just assign the variable directly
var serviceData= dtPasscode ...
var userData = DisplyCustomerDetails ...
var result = serviceData.Concat(userData);

In Swift, what is the best way to assign two arrays to key/value of a dictionary?

Suppose I have two arrays:
let myKeys = ["one", "two", "three"]
let myValues = ["1", "2", "3"]
and empty dictionary:
var myDictionary = Dictionary<String, String>()
What is the best way to assign myKeys and myValues as keys and values, respectively, of myDictionary?
With my knowledge, this is the way to assign values/keys for your dictionary:
let count = myKeys.count
let count2 = myValues.count
if (count == count2) {
for index in 0..count {
myDictionary.updateValue(myValues[index], forKey:myKeys[index])
}
}
Edit: Swift 2
let count = myKeys.count
let count2 = myValues.count
if (count == count2) {
for index in 0 ..< count {
myDictionary.updateValue(myValues[index], forKey:myKeys[index])
}
}

Extracting values of textbox in array?

I have dynamically created textbox in asp.net. Now i am extracting the values through following code.
string[] sublist = new string[] { };
int[] maxmarkslist = new int[] { };
int i;
for (i = 0; i < Convert.ToInt32(Label15.Text); i++)
{
string sub = "subject" + i;
string marks = "maxmarks" + i;
TextBox subject = (TextBox)PlaceHolder1.FindControl(sub);
TextBox maxmarks = (TextBox)PlaceHolder1.FindControl(marks);
sublist[i] = subject.Text;
maxmarkslist[i] = Convert.ToInt32(maxmarks.Text);
}
But I getting error "Index was outside the bounds of the array" for the below two lines:
sublist[i] = subject.Text;
maxmarkslist[i] = Convert.ToInt32(maxmarks.Text);
When I debugged it, values are coming in subject.Text and maxmarks.Text but not going to array.
Did I define the array in a wrong way?
You define both the arrays as empty arrays. So you will get index out of bound erros if you try to index into those.
Arrays are not dynamically expanding. If you want that, use a collection type and may be later convert to an array.
Try this:
int length = Convert.ToInt32(Label15.Text);
string[] sublist = new string[length-1];
int[] maxmarkslist = new int[length-1];
for (int i = 0; i < length; i++)
{
string sub = "subject" + i;
string marks = "maxmarks" + i;
TextBox subject = (TextBox)PlaceHolder1.FindControl(sub);
TextBox maxmarks = (TextBox)PlaceHolder1.FindControl(marks);
sublist[i] = subject.Text;
maxmarkslist[i] = Convert.ToInt32(maxmarks.Text);
}
Or here is how to do this with a collection (List) type:
int length = Convert.ToInt32(Label15.Text);
List<string> sublist1 = new List<string>();
List<int> maxmarkslist1 = new List<int>();
for (int i = 0; i < Convert.ToInt32(Label15.Text); i++)
{
string sub = "subject" + i;
string marks = "maxmarks" + i;
TextBox subject = (TextBox)PlaceHolder1.FindControl(sub);
TextBox maxmarks = (TextBox)PlaceHolder1.FindControl(marks);
sublist1.Add(subject.Text);
maxmarkslist1.Add(Convert.ToInt32(maxmarks.Text));
}
string[] sublist = sublist1.ToArray();
int[] maxmarkslist = maxmarkslist1.ToArray();
Note with collections you dont have to specify the size upfront. But keep adding items to it as it can expand as needed. But arrays can not do this.
Your string[] sublist = new string[] { }; is a shortcut method where you create and initialize the array. In that you don't have to specify the size, but compiler will count the elements between {} and set the size appropriately. In your case since there are no elements inside {} it will create an empty array.
string[] sublist = new string[100];
int[] maxmarkslist = new int[100];
Put this..replace 100 with the max possible value of your loop...but this is not a good practice...will come back to this thread if i found something better...

queries in entity framework

i have written the following query and it is giving error Unable to cast object of type
System.Data.Objects.ObjectQuery'[ITClassifieds.Models.Viewsearch]' to type 'ITClassifieds.Models.Viewsearch'.
my code is as follows
if (zipcode.Contains(","))//opening of zipcode conatins comma
{
do
{
zipcode = zipcode.Replace(" ", " ");
zipcode = zipcode.Replace(", ", ",");
} while (zipcodecity.Contains(" "));
char[] separator = new char[] { ',' };
string[] temparray = zipcode.Split(separator);
var zipcd = (from u in db.ZipCodes1
where u.CityName == temparray[0] && u.StateAbbr == temparray[1] && u.CityType == "D"
select new Viewsearch
{
Zipcode = u.ZIPCode
}).Distinct();
Viewsearch vs = (Viewsearch)zipcd;
if (zipcd.Count() > 0)
{
zipcode = vs.Zipcode;
locations = "";
}
else
{
tempStr = "";
zipcode = "";
}
}
You need to do
If it will always exist:
Viewsearch vs = zipcd.First()
If not use, and then check for null before using
Viewsearch vs = zipcd.FirstOrDefault()
You could also use Single if there will always be 1 or None.
The Distinct method returns an enumerable collection (in your case, and ObjectQuery<T>, which may contain more than one element. You can't typecast that directly to an item in the collection, you need to use one of the IEnumerable methods to get it:
Viewsearch vs = zipcd.SingleOrDefault();
if ( vs != null )
{
zipcode = vs.Zipcode;
locations = String.Empty;
}
else
{
zipcode = String.Empty;
tempStr = String.Empty;
}
SingleOrDefault will throw an exception if there is more than one item in the collection; if that's a problem, you can also use FirstOrDefault to grab the first item, as one example.
Also, unrelated to your question, but you don't need the temporary array variable for your string separators. The parameter to the Split method is a params array so you can just call it like this:
string[] temparray = zipcode.Split(',');
Replace the zipcd query with:
var cityName = temparray[0];
var stateAbbr = temparray[1];
Viewsearch vs = new Viewsearch {
Zipcode = db.ZipCodes1.Where(u.CityName == cityName && u.StateAbbr == stateAbbr && u.CityType == "D").First().ZIPCode
};

Resources