how to skip multiple iterations and improve code - c#

In the below C# code, I am doing 2 iterations over data and trying to create a filter that looks like this,
(Name1 = 'd1' AND Name2 = 'd1') OR (Name1 = 'd3' AND Name2 = 'd3') OR (Name1 != 'd1' AND Name1 != 'd3')
For the below sets of data:
var data = new List<(string, string)>
{
("d1", "d2"), ("d3", "d4"),
};
Here is code:
foreach(var entity in data)
{
filter += $"(Name1 = '{entity.Item1}' AND Name2 = '{entity.Item1}') OR ";
}
filter = filter + "(";
foreach (var entity in data)
{
filter += $"Name1 != '{entity.Item1}' AND ";
}
//remove last "AND"
var final = filter.Substring(0, filter.LastIndexOf("AND")).TrimEnd() + ")";
How I can improve this code and get rid of 2 iterations? Thanks.

Use Linq and string.Join to iterate once and avoid SubString:
var data = new List<(string, string)> { ("d1", "d2"), ("d3", "d4"), };
var exclude = new List<string>();
var filters = string.Join(" OR ", data.Select(entity => {
exclude.Add($"Name1 != '{entity.Item1}'");
return $"(Name1 = '{entity.Item1}' AND Name2 = '{entity.Item1}')";
}));
string final = $"{filters} OR ({string.Join(" AND ", exclude)})";

You can have two filter strings which you build up simultaneously and then combine at the end:
string filter = "";
string filter2 = "";
var data = new List<(string, string)>
{
("d1", "d2"), ("d3", "d4"),
};
foreach(var entity in data)
{
filter += $"(Name1 = '{entity.Item1}' AND Name2 = '{entity.Item1}') OR ";
filter2 += $"Name1 != '{entity.Item1}' AND ";
}
filter2 = filter2.Substring(0, filter2.LastIndexOf("AND")).TrimEnd();
string final = $"{filter}({filter2})";
Live demo: https://dotnetfiddle.net/TGr6Jz

Related

I want to load a text file into a data grid and apply a regular expression

string[] s = File.ReadAllLines(ofdl.FileName);
List<code> codes = new List<code>();
string textfile = ofdl.FileName;
var textvalues = s;
foreach (var item in textvalues)
{
codes.Add(new code() { Value = RemoveEmptyLines(item) });
}
dataGrid.ItemsSource = codes;
under_label.Content = textfile;
under_label1.Content = codes.Count();
private string RemoveEmptyLines(string lines)
{
return lines = Regex.Replace(lines, #"\n\s.+", "");
}
I want to load a text file into a data grid and apply a regular expression
but this code don't work for me
you don't need Regex to search for empty strings. String.IsNullOrWhiteSpace() method will do.
string[] lines = File.ReadAllLines(ofdl.FileName);
var codes = lines.Where(s => !String.IsNullOrWhiteSpace(s)).ToList();
dataGrid.ItemsSource = codes;
under_label.Content = ofdl.FileName;
under_label1.Content = codes.Count;
datagrid
I want to exclude the part of the circle separately
List<code> codes = new List<code>();
string[] s = File.ReadAllLines(ofdl.FileName);
string textfile = ofdl.FileName;
var textvalues = s;
foreach (var item in textvalues)
{
codes.Add(new code() { Value = item});
}
dataGrid.ItemsSource = codes;
}
}
}
private void streams()
{
}
private string RemoveEmptyLines(string lines)
{
return lines = Regex.Replace(lines, #"\n\s.+", "");
}

C# scoring based on answers

I have some data that has values in properties called Poll_1, Poll_2, Poll_3, ...Poll_8.
I need to get a score based on this criteria:
For each Poll_1 thru Poll_4 that is not empty, FirstPollCount is incremented.
For each Poll_5 thru Poll_8 that is not empty, SecondPollCount is incremented.
This is currently how I'm doing it.
int pass1 = 0;
int pass2 = 0;
if (rec.Poll_1.Trim() != "") { pass1++; };
if (rec.Poll_2.Trim() != "") { pass1++; };
if (rec.Poll_3.Trim() != "") { pass1++; };
if (rec.Poll_4.Trim() != "") { pass1++; };
if (rec.Poll_5.Trim() != "") { pass2++; };
if (rec.Poll_6.Trim() != "") { pass2++; };
if (rec.Poll_7.Trim() != "") { pass2++; };
if (rec.Poll_8.Trim() != "") { pass2++; };
aa.FirstPollCount = pass1;
aa.SecondPollCount = pass2;
Is there an easier way to do this?
Not really any better, but if you want to look to an alternative
List<string> firstPolls = new List<string>()
{
rec.Poll_1.Trim(), rec.Poll_2.Trim(),rec.Poll_3.Trim(),rec.Poll_4.Trim()
};
int pass1 = firstPolls.Count(x => x != "");
List<string> secondPolls = new List<string>()
{
rec.Poll_5.Trim(), rec.Poll_6.Trim(),rec.Poll_7.Trim(),rec.Poll_8.Trim()
};
int pass2= secondPolls.Count(x => x != "");
By the way, what is the class for the rec variable? Probably an improvement is to add a internal method that executes this code and returns the value:
int pass1 = rec.GetFirstScoreCount();
int pass2 = rec.GetSecondScoreCount();
thus hiding the implementation details (the Trim() != "") from the client code that uses the rec variable.
You can use Linq:
string s1 = "Random String";
string s2 = "Random String";
string s3 = "Random String";
string s4 = "Random String";
string s5 = "Random String";
string s6 = "";
string s7 = "Random String";
string s8 = "Random String";
int countPool1 = (new List<string>(){s1, s2, s3, s4}).Count(t => t.Trim() != "");
int countPool2 = (new List<string>() { s5, s6, s7, s8 }).Count(t => t.Trim() != "");
Console.Out.WriteLine("Pool 1 : " + countPool1);
Console.Out.WriteLine("Pool 2 : " + countPool2);
With output:
Pool 1 : 4
Pool 2 : 3
You can also use Linq Query Syntax:
List<string> pol1to4Coll = new List<string>() { rec.Poll_1, rec.Poll_2, rec.Poll_3, rec.Poll_4 };
List<string> pol5to8Coll = new List<string>() { rec.Poll_5, rec.Poll_6, rec.Poll_7, rec.Poll_8 };
int countPol1to4Coll = (from poll in pol1to4Coll
where poll != ""
select poll).Count();
int countPol5to8Coll = (from poll in pol5to8Coll
where poll != ""
select poll).Count();

Neo4jClient Union

Can any body help me to convert this Cypher Query to neo4jclient?
MATCH (o)-[r]-(post:Post)-[:HAS_MentionedUsers]->(assignee1307989068:User),
WHERE (assignee1307989068.UserName = "mhs")
RETURN post,o,r
UNION
MATCH (o)-[r]-(post:Post)-[:HAS_HashTags]-> (Hashtag1841024507:HashTag)
WHERE (Hashtag1841024507.Value = "myTag")
RETURN post,o,r
Is there any Idea how to create the above cypher query dynamically based on User input which whould be "mhs" and "myTag" in C# and neo4jClient?
Here is what I havetried so far:
The search method will get the search term and tokenize it then BuildPostQueystring method will add each part of the cypher query .
public Object Search(string searchterm)
{
List<string> where = new List<string>();
var tokenizedstring = searchterm.Split(' ');
var querystring = new StringBuilder();
int unionCount = 0;
var q = new CypherFluentQuery(_graphClient) as ICypherFluentQuery;
foreach (var t in tokenizedstring)
{
_commandService.BuildPostQueystring(t, ref querystring, ref where);
if (querystring[querystring.Length - 1] == ',')
querystring = querystring.Remove(querystring.Length - 1, 1);
if (unionCount > 0)
q = q.Union();
q = q.Match(querystring.ToString());
unionCount++;
int i = 1;
if (where.Count > 0)
q = q.Where(where[0]);
while (i < where.Count)
{
q = q.OrWhere(where[i]);
i++;
}
q = q.Return((post, nodes) => new { Post = post.As<Node<string>>(), Nodes = nodes.As<Node<string>>() })
.OrderBy("post.creationDate");
where.Clear();
querystring.Clear();
}
//var rq = q.Return((post, o) => new {Person = post.As<Node<string>>(), Dog = o.As<Node<string>>()})
// .OrderBy("post.creationDate");
var x = (q as CypherFluentQuery<dynamic>).Results;
return x.ToList();
}
The other method that add the query part is as fallow :
public void BuildPostQueystring(string token, ref StringBuilder sb, ref List<string> whereConditions)
{
string querystring = "(nodes)-[r]-(post:Post)-[:HAS_{0}]->({1}:{2})";
string wherestring = "({0}.{1} = \"{2}\")";
if (token.StartsWith("#"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash*-1;
string paramName = "Hashtag" + hash;
var str = string.Format(querystring, "HashTags", paramName, "HashTag");
var tvalue = token.Replace("#", "");
//query = query.AndWhere((HashTag hashTag) => hashTag.Value == tvalue);
sb.Append(str);
whereConditions.Add(string.Format(wherestring, paramName, "Value", tvalue));
}
else if (token.StartsWith("+"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "team" + hash;
var str = string.Format(querystring, paramName, "MentionedTeam","Team");
sb.Append(str);
var tvalue = token.Replace("+", "");
whereConditions.Add(string.Format(wherestring,paramName, "Name", tvalue));
}
else if (token.StartsWith("#"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "assignee" + hash;
var str = string.Format(querystring, "MentionedUsers", paramName, "User");
sb.Append(str);
var tvalue = token.Replace("#", "");
whereConditions.Add(string.Format(wherestring, paramName,"UserName", tvalue));
}
else if (token.StartsWith("by"))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "author" + hash;
var str = string.Format(querystring, "Author", paramName, "User");
sb.Append(str);
var tvalue = token.Replace("by:", "");
whereConditions.Add(string.Format(wherestring, paramName, "UserName", tvalue));
}
else if (token.Contains("\\"))
{
foreach (var dt in GetLocalDateTokens(_dateTimeTokens))
{
int hash = token.GetHashCode();
if (hash < 0)
hash = hash * -1;
string paramName = "dueDate" + hash;
if (token.ToLower() == dt.Text.ToLower())
{
var neodate = new NeoDateTime();
neodate.Year = dt.GetDate.Year;
neodate.Month = dt.GetDate.Month;
neodate.Day = dt.GetDate.Day;
neodate.TimeStamp = long.Parse(dt.GetDate.ToString("HHmmss"));
neodate.DateStamp = long.Parse(dt.GetDate.ToString("yyyyMMdd"));
neodate.DateTimeStamp = long.Parse(dt.GetDate.ToString("yyyyMMddHHmmss"));
var str = string.Format(querystring, "DueDates", paramName, "NeoDateTim");
sb.Append(str);
var tvalue = token.Replace("by:", "");
whereConditions.Add(string.Format(wherestring, "DateStamp", paramName, tvalue));
}
}
}
else
{
//MATCH (n)
//WHERE n.name =~ 'Tob.*'
//RETURN n
var wherestr = "({0}.{1} =~ '{2}.*')";
//string wherestring = "({0}.{1} = \"{2}\")";
//string querystring = "(post:Post)-[:HAS_{0}]->({1}:{2})";
string paramName = "post" + token + GetHashCode();
string qs = "(post:Post)";
var str = string.Format(qs, paramName);
sb.Append(str);
whereConditions.Add(string.Format(wherestr, "post", "Text", token));
}
if(sb.Length>0)
sb.Append(",");
}
My first problem is how to get result as the q does not have the result method and I cant cast it to an anonymous type?!
OK, firstly, the reason q doesn't have a Results method is because up until you add a Return call you only have an ICypherFluentQuery, so if you have:
var query = client.Cypher.Match("(n:Post)");
query will be of type ICypherFluentQuery which doesn't have a Results method, once you add a Return statement:
var query = client.Cypher.Match("(n:Post)").Return(n => n.As<Post>());
you'll find the query is now: ICypherFluentQuery<Post>. So, before you add your .Return statement, you will need to assign to another variable:
var query = client.Cypher.Match("(n:Post)");
var retQuery = query.Return(n => n.As<Post>());
var results = retQuery.Results;
Second part, the actual query.
It's not entirely clear what you're trying to do with your code, you have a lot of it, but the code for your query (in my view) should look something like this:
private void GetResults(string username, string tagValue)
{
var query = Client.Cypher
.Match("(o)-[r]-(post:Post)-[:HAS_MentionedUsers]->(assignee:User)")
.Where((User assignee) => assignee.UserName == username)
.Return((post, o, r) => new {Post = post.As<Post>(), O = o.As<object>(), R = r.As<RelationshipInstance<object>>()})
.Union()
.Match("(o)-[r]-(post:Post)-[:HAS_MentionedUsers]->(hashTag:HashTag)")
.Where((HashTag hashTag) => hashTag.Value == tagValue)
.Return((post, o, r) => new {Post = post.As<Post>(), O = o.As<object>(), R = r.As<RelationshipInstance<object>>()});
var res = query.Results.ToList();
}
PS: I have no idea what type o is, so I have used object as a placeholder
If for some reason you need to use those names assignee1307989068 etc as you're building up an epic query then the where would become something like:
/* MATCH */
.Where("assignee123.Value == {assignee123Param}")
.WithParam("assignee123", username)
/* RETURN */
If you can, I would go with the first version as it's type safe and easier to understand.

What is an efficient way of iterating through a list according to its distinct values?

string sStoreStockFeed = "";
string sSeparator = "";
var distinctStoreIDList = skuStoreStockLevels.Select(x => x.Item1).Distinct();
foreach (var storeID in distinctStoreIDList)
{
foreach (var item in skuStoreStockLevels)
{
if (item.Item1 == storeID)
{
// add this one to a job for this store
sStoreStockFeed += sSeparator + item.Item1.ToString() + "," + item.Item2.ToString() + "," + item.Item3.ToString();
sSeparator = "|";
}
}
// some code to process the string before moving on
sStoreStockFeed = "";
sSeparator = "";
}
In the above code snippet skuStoreStockLevels just happens to be a List of type Tuple and Item1 is the StoreID. having got a distinct list it then iterates through the (non-distinct) list to get every applicable item. The inefficiency is that the (big) inner list is iterated throuh repeatedly for each distinct item (StoreID).
UPDATE: pure LINQ solution. This will give you list of strings, created for each group of items.
var query = skuStoreStockLevel.GroupBy(x => x.Item1)
.Select(g => g.Aggregate(new StringBuilder(),
(sb, x) => sb.AppendFormat("{0}{1},{2},{3}", sSeparator, x.Item1, x.Item2, x.Item3),
(sb) => sb.ToString()));
foreach(var feed in query)
// some code to process the string before moving on
Also there are other options - ordering of sequence. Equal items will follow one after another.
int storeID = -1;
StringBuilder builder = new StringBuilder();
foreach (var item in skuStoreStockLevel.OrderBy(x => x.Item1))
{
builder.AppendFormat("{0}{1},{2},{3}", sSeparator, item.Item1, item.Item2, item.Item3);
if (item.Item1 != storeID)
{
// some code to process the string before moving on
storeID = item.Item1;
}
}
Or you can use grouping
StringBuilder builder = new StringBuilder();
foreach (var storeGroup in skuStoreStockLevel.GroupBy(x => x.Item1))
{
foreach (var item in storeGroup)
builder.AppendFormat("{0}{1},{2},{3}", sSeparator, item.Item1, item.Item2, item.Item3);
// some code to process the string before moving on
}
And, of course, it's better to use StringBuilder for creating strings.
Use Linq GroupBy which will build you a list of grouped items:
string sStoreStockFeed = "";
string sSeparator = "";
var itemsByStore = skuStoreStockLevels.GroupBy(x => x.Item1);
foreach (var storeItems in itemsByStore )
{
// storeItems.Key is the storeId, that is x.Item1
foreach(var item in storeItems)
{
sStoreStockFeed += sSeparator + item.Item1.ToString() + "," + item.Item2.ToString() + "," + item.Item3.ToString();
sSeparator = "|";
}
// some code to process the string before moving on
sStoreStockFeed = "";
sSeparator = "";
}

Converting Datatable to ienumerable<anonymous>?

is it possible to convert data table to ienumerable without know its class name.
my requirement is to convert table
First | Last
--------------
john | mcgill
clara | linda
to
{{First:john,Last:mcgill},{First:clara ,Last:linda}}
Ienumerable collection
i dont want to use dynamic object because dynamic object supports only frame work 4.
thanks
var results = from row in dataTable.AsEnumerable()
select new {
First = row.Field<string>("First"),
Last = row.Field<string>("Second")
};
You'll need System.Data.DataSetExtensions.
You can use Anonymous Types - they were introduced with .NET 3.5.
Syntax for that kind of objects is really clear and intuitive:
var item = new { First = "First-Value", Last = "Last-Value" }
and the query:
var items = dataTable.AsEnumerable()
.Select(i => new {
First = i.Field<string>("First"),
Last= i.Field<string>("Last")
});
No column names please!
public string ConvertDataTableToString(DataTable table)
{
int iColumnCount = table.Columns.Count;
int iRowCount = table.Rows.Count;
int iTempRowCount = 0;
string strColumName = table.Columns[0].ColumnName;
string strOut = "{";
foreach (DataRow row in table.Rows)
{
strOut = strOut + "{";
foreach (DataColumn col in table.Columns)
{
string val = row.Field<string>(col.ColumnName);
strOut = strOut + col.ColumnName + ":" + val;
if (col.Ordinal != iColumnCount - 1)
{
strOut = strOut + ",";
}
}
strOut = strOut + "}";
iTempRowCount++;
if (iTempRowCount != iRowCount)
{
strOut = strOut + ",";
}
}
strOut = strOut + "}";
return strOut;
}
It is a fairly easy job using anonymous types. Here is a complete example that only requires classes from the System.Linq and System.Data namespaces:
class Program
{
static void Main(string[] args)
{
DataTable dataTable = new DataTable();
dataTable.Columns.Add().ColumnName = "First";
dataTable.Columns.Add().ColumnName = "Last";
var row = dataTable.NewRow();
row["First"] = "hello";
row["Last"] = "world";
dataTable.Rows.Add(row);
var query = dataTable.Rows.Cast<DataRow>()
.Select(r => new
{
First = r["First"],
Last = r["Last"]
});
foreach (var item in query)
Console.WriteLine("{0} {1}", item.First, item.Last);
}
}

Categories

Resources