private void categoryCheckedListBox_ItemCheck(object sender, DevExpress.XtraEditors.Controls.ItemCheckEventArgs e)
{
if (e.State==CheckState.Checked)
{
string categoryName = categoryCheckedListBox.Items[e.Index].Value.ToString();
(productListGV.DataSource as DataTable).DefaultView.RowFilter = string.Format("Kata2 LIKE '%{0}%' AND Kata1 LIKE '%{1}%'", categoryName,Cins);
}
else
{
(productListGV.DataSource as DataTable).DefaultView.RowFilter = null;
}
}
Hello Category always sounds different and dynamic. What I want is to add it to the filter for each selected checkbox value. CategoryName can have different value.
I did DefaultView.RowFilter+=.... but is error.
Iterate over categoryCheckedListBox.Items, compose your string.Format String based on the iterations and then pass to the string.Formats Object an array with the checked corresponding strings.
Example:
using System;
using System.Linq;
// Lacking actual data, I made an assumption that Kata concatenated with the key will correspond to the actual column
(productListGV.DataSource as DataTable).DefaultView.RowFilter = string.Join(" AND ", new[] { "a", "b", "c" }.Select((val, key) => $"Kata{key} LIKE '%{val}%'" ));
Or:
using System;
string[] a = new[] { "a", "b", "c" };
string s = String.Empty;
for (int i = 0; i < a.Length; i++) s+= $"Kata{i} LIKE '%{a[i]}%'";
(productListGV.DataSource as DataTable).DefaultView.RowFilter = string.Format(s, a);
I believe you get the picture.
Related
I am writing a logic something like following code -
string myString = "ABCD";
if(myString.Contains("AB") && myString.Contains("C") && !myString.Contains("XYZ"))
{
//Do something
}
I want to write above code something like this:
string myString = "ABCD";
if( myString .contains any string from new[] { "AB", "C" } )
{
//Do Something
}
Can you please tell me, How can I achieve it?
Thanks in advance.
You want to check if the array has Any item such that myString Contains it:
using System.Linq;
...
// myString contains "AB" or "C"
if (new[]{ "AB", "C" }.Any(item => myString.Contains(item))) {
...
}
Put All it myString should contains both "AB" and "C"
// myString contains both "AB" and "C"
if (new[]{ "AB", "C" }.All(item => myString.Contains(item))) {
...
}
How about a little string extension method?
public static class StringExt
{
public static bool ContainsAnyOf(this string self, params string[] strings)
{
return strings.Any(self.Contains);
}
}
Then you can do this:
if (myString.ContainsAnyOf("AB", "C") && !myString.Contains("XYZ"))
{
//Do something
}
This sounds like a candidate for an extension method!
public static class StringExtensions
{
public static bool Contains(this string self, params string[] values)
{
for(int ix = 0; ix < values.Length; ++ix)
if(!self.Contains(values[ix]))
return false;
return true;
}
}
For your code like:
string myString = "ABCD";
if(myString.Contains("AB") && myString.Contains("C") && !myString.Contains("XYZ"))
{
//Do something
}
Let's do all your checks using LINQ:
var theStr = "ABCD";
var rules = new string[]{ "AB", "C", "!XYZ"};
if(rules.All(rule => rule[0] == '!' ? !theStr.Contains(rule.Substring(1)) : theStr.Contains(rule)))
{
//Do something
}
I do feel it's perhaps a mild abuse to put the "not" into the data by prefixing it with "!" though; consider making a Rule class that has a string and an Enum of RuleType that defines whether that string should be searched as "Contains" or "Not Contains".. Especially if you are ever going to want to find strings where one of the things you're looking for really is a string that starts with an "!"
You can use .All() because you are trying to check all strings present in an array
var checkElements = new string[]{ "AB", "C"};
//All element contains in myString then this will return true. It checks all elements
if(checkElements.All(x => myString.Contains(x)))
{
//Your business logic
}
If you want to check, if any string from an array checkElements, present in myString then you can use .Any() from System.Linq
var checkElements = new string[]{ "AB", "C"};
//Any one element contains in myString then this will return true.
if(checkElements.Any(x => myString.Contains(x)))
{
//Your business logic
}
I am trying to get the some specific fields from dynamic object with is actually a list of any class, this class contains various fields out of those fields I want to select some specific fields using LINQ, The fields which I want to select is also passing by the user. Below is the code that I have tried using System.Linq.Dynamic.
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Linq.Dynamic;
using System.Collections;
private void Test_Click(object sender, EventArgs e)
{
List<RateInfo> lst = new List<RateInfo>();
lst.Add(new RateInfo() { id_country = "IND", id_state = 1, rate = 2.3f });
lst.Add(new RateInfo() { id_country = "IND", id_state = 2, rate = 1.1f });
lst.Add(new RateInfo() { id_country = "IND", id_state = 3, rate = 5.2f });
lst.Add(new RateInfo() { id_country = "IND", id_state = 4, rate = 6.5f });
GetDynamicData(lst, new List<string>() { "id_country", "id_state" });
}
private void GetDynamicData(dynamic list, List<string> fetchFields)
{
var data = ((IEnumerable)list).Cast<dynamic>()
.Select(r => new { r }).AsQueryable();
StringBuilder s = new StringBuilder();
//This is for test only.
//It works, the value of "id_state" and "id_state" getting appended
foreach (var item in data)
{
s.Append(item.r.id_state);
s.Append(",");
s.Append(item.r.id_country);
}
//-----------------------------------------------------
//Select the specific field data from dynamic list
StringBuilder fields = new StringBuilder();
fields.Append("new (");
foreach (var fld in fetchFields)
{
fields.Append("r." + fld);
fields.Append(",");
}
fields.Remove(fields.Length - 1, 1);
fields.Append(")");
//This does not work throws error
//"No property or field 'id_country' exists in type 'Object'"
IQueryable iq = data.Select(fields.ToString());
//For test only to check the value of selected fields
foreach (dynamic item in iq)
{
s.Append(item.id_state);
s.Append(",");
s.Append(item.id_country);
}
}
you can hughly simplify your GetDynamicData method both specifying explicit list type (GetDynamicData(IList<RateInfo> list, ...)) and leaving the list item type generic, in order to reuse the method; with this last approach in mind, you can rewrite the GetDynamicData as follows, obtaining the desired output:
private void GetDynamicData<T>(IEnumerable<T> list, List<string> fetchFields)
{
var fields = $"new ({string.Join(",", fetchFields)})";
var res = list.AsQueryable().Select(fields);
//For test only to check the value of selected fields
foreach (dynamic item in res) {
Console.WriteLine(item.id_state);
Console.WriteLine(item.id_country);
}
}
OUTPUT
1
IND
2
IND
3
IND
4
IND
EXPLANATION
I think the difference is that specifying explicitly the type (through generic T or through RateInfo) you force LINQ to know list items'type; if you use dynamic the IQueryable.ElementType of the IQuqryable instance has value System.Object, so the query fails with the error you've experienced.
You should try using generics:
private void GetDynamicData<T>(IEnumerable<T> list, List<string> fetchFields)
{
var data = list.AsQueryable();
I have a list of strings and stringOutput as example:
readonly List<string> carMake = new List<string>
{
"Toyota",
"Honda",
"Audi",
"Tesla"
};
string myFunction()
{
// do some processing...
string stringOutput = CallGetLatestRecord();
// the above returns "a:toyota:c"
//Call another function after changing the string to "a:Toyota:c"
//I am planning to use **stringOutput.Replace**
//but don't know how to get toyota or list items values dynamically
callFoo(stringOutput);
}
So this is what I want. If my:
stringOutput contains "a:toyota:c", I would like to update it to "a:Toyota:c" using carMake.
stringOutput contains "a:audi:c", I would like to update it to "a:Audi:c" using carMake.
How do I convert this using Linq ?
Also, note that at runtime I dont know if it is toyota or any string... so I want a generic solution using Linq
Something like below should help you get started...
using System.Text.RegularExpressions;
string stringOutput = "a:toyota:c";
readonly List<string> carMake = new List<string>
{
"Toyota",
"Honda",
"Audi",
"Tesla"
};
string pattern = #".+?:(.+?):.+?";
foreach (Match m in Regex.Matches(stringOutput, pattern))
{
if (carMake.Any(s=>s.Equals(m.Groups[1].Value, StringComparison.InvariantCultureIgnoreCase)))
{
stringOutput = stringOutput.Replace(m.Groups[1].Value, carMake.First(s=>s.Equals(m.Groups[1].Value, StringComparison.InvariantCultureIgnoreCase)));
}
}
Console.WriteLine(stringOutput);
You can do something like this;
string Process(string stringOutput)
{
foreach (string c in carMake)
{
int i = stringOutput.IndexOf(c.ToLower());
if (i > -1)
{
stringOutput=stringOutput.Replace(c.ToLower(), c);
}
}
return stringOutput;
}
I have a method that takes this parameter
params string[] additionalParameters
I am building it like this:
qsParams = new string[] {"k=" + k, "l=" + l, "o=" + o, "s=" + s, "t=" + t, "h=" + h, "exp=" + exp };
These are url params. The problem is I only want to add parameters where the variables are not null or empty.
I can do this kind of thing:
if (string.IsNullOrEmpty(k))
{
qsParams = new string[] {"l=" + l, "o=" + o, "s=" + s, "t=" + t, "h=" + h, "exp=" + exp };
}
But that's going to get complicated and ugly trying to handle all the different permutations of empty variables.
Can anyone suggest a simple way to add the params if there are not null? Perhaps a list that I can convert to a params []string?
public static void Main(string[] args)
{
List<string> parameters = new List<string>();
string k = "a";
string l = null;
AddParam("k", k, parameters);
AddParam("l", l, parameters);
string[] result = parameters.ToArray();
}
public static void AddParam(string paramName, string paramValue, List<string> parameters)
{
if (string.IsNullOrEmpty(paramValue))
return;
parameters.Add(paramName + "=" + paramValue);
}
You can try something like this.
You can write a method that returns null if your variable has no value:
private string GetListValue(string prefix, string value) {
if (String.IsNullOrEmpty(value)) {
return null;
}
else {
return prefix + value;
}
}
You can define your raw list with this method (only using 2 values):
string[] rawList = { GetListValue("k=", k), GetListValue("l=", l) };
Then clean the list with LINQ:
string[] cleanValues = rawValues.Where(v => v != null).ToArray();
If your params are always in right order:
List<string> qsParams = new List<string>();
string[] paramNames = new string[] { "k", "l", "o", "s", "t", "h", "exp" };
for (int i = 0; i < additionalParameters.Length; i++)
{
if (!string.IsNullOrEmpty(additionalParameters[i]))
{
qsParams.Add(string.Format("{0}={1}", paramNames[i], additionalParameters[i]));
}
}
Just create a dictionary with the key being the param and the value being well... the value.
Dictionary<string, string> Parameters = new Dictionary<string, string>();
Parameters.Add("k", "myKValue");
Parameters.Add("o", "myOValue");
string paramaterList = string.Join("&", Parameters.Select(x => $"{x.Key}={x.Value}"));
Only add values to the dictionary when they aren't null.
I have a CSV that is delivered to my application from various sources. The CSV will always have the same number columns and the header values for the columns will always be the same.
However, the columns may not always be in the same order.
Day 1 CSV may look like this
ID,FirstName,LastName,Email
1,Johh,Lennon,jlennon#applerecords.com
2,Paul,McCartney,macca#applerecords.com
Day 2 CSV may look like this
Email,FirstName,ID,LastName
resident1#friarpark.com,George,3,Harrison
ringo#allstarrband.com,Ringo,4,Starr
I want to read in the header row for each file and have a simple mechanism for associating each "column" of data with the associated property I have defined in my class.
I know I can use selection statements to figure it out, but that seems like a "bad" way to handle it.
Is there a simple way to map "columns" to properties using a dictionary or class at runtime?
Use a Dictionary to map column heading text to column position.
Hard-code mapping of column heading text to object property.
Example:
// Parse first line of text to add column heading strings and positions to your dictionary
...
// Parse data row into an array, indexed by column position
...
// Assign data to object properties
x.ID = row[myDictionary["ID"]];
x.FirstName = row[myDictionary["FirstName"]];
...
You dont need a design pattern for this purpose.
http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader
I have used this Reader, while it is pretty good, it has a functionality as row["firstname"] or row["id"] which you can parse and create your objects.
I have parsed both CSV files using Microsoft.VisualBasic.FileIO.TextFieldParser. I have populated DataTable after parsing both csv files:
DataTable dt;
private void button1_Click(object sender, EventArgs e)
{
dt = new DataTable();
ParseCSVFile("day1.csv");
ParseCSVFile("day2.csv");
dataGridView1.DataSource = dt;
}
private void ParseCSVFile(string sFileName)
{
var dIndex = new Dictionary<string, int>();
using (TextFieldParser csvReader = new TextFieldParser(sFileName))
{
csvReader.Delimiters = new string[] { "," };
var colFields = csvReader.ReadFields();
for (int i = 0; i < colFields.Length; i++)
{
string sColField = colFields[i];
if (sColField != string.Empty)
{
dIndex.Add(sColField, i);
if (!dt.Columns.Contains(sColField))
dt.Columns.Add(sColField);
}
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
if (fieldData.Length > 0)
{
DataRow dr = dt.NewRow();
foreach (var kvp in dIndex)
{
int iVal = kvp.Value;
if (iVal < fieldData.Length)
dr[kvp.Key] = fieldData[iVal];
}
dt.Rows.Add(dr);
}
}
}
}
day1.csv and day2.csv as mentioned in the question.
Here is how output dataGridView1 look like:
Here is a simple generic method that will take a CSV file (broken into string[]) and create from it a list of objects. The assumption is that the object properties will have the same name as the headers. If this is not the case you might look into the DataMemberAttribute property and modify accordingly.
private static List<T> ProcessCSVFile<T>(string[] lines)
{
List<T> list = new List<T>();
Type type = typeof(T);
string[] headerArray = lines[0].Split(new char[] { ',' });
PropertyInfo[] properties = new PropertyInfo[headerArray.Length];
for (int prop = 0; prop < properties.Length; prop++)
{
properties[prop] = type.GetProperty(headerArray[prop]);
}
for (int count = 1; count < lines.Length; count++)
{
string[] valueArray = lines[count].Split(new char[] { ',' });
T t = Activator.CreateInstance<T>();
list.Add(t);
for (int value = 0; value < valueArray.Length; value++)
{
properties[value].SetValue(t, valueArray[value], null);
}
}
return list;
}
Now, in order to use it just pass your file formatted as an array of strings. Let's say the class you want to read into looks like this:
class Music
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
So you can call this:
List<Music> newlist = ProcessCSVFile<Music>(list.ToArray());
...and everything gets done with one call.