I need to select distinct rows from Textfile display below.
TextFile
123| one| two| three <br/>
124| one| two| four <br/>
125| one |two| three <br/>
Output should like this
123| one| two| three <br/>
124| one| two| four <br/>
OR
124| one| two| four <br/>
125| one |two| three <br/>
I am using this code to work out this problem
var readfile = File.ReadAllLines(" text file location ");
var spiltfile = (from f in readfile
let line = f.Split('|')
let y = line.Skip(1)
select (from str in y
select str).FirstOrDefault()).Distinct()
Thanks
The unclear spacing in the question doesn't help (especially around the |two|, which has different spacing than the rest, implying we need to use trimming), but here's some custom LINQ methods that do the job. I've used the anon-type purely as a simple way of flattening out the inconsistent spacing (I could also have rebuilt a string, but it seemed unnecessary)
Note that without the odd spacing, this can be simply:
var qry = ReadLines("foo.txt")
.DistinctBy(line => line.Substring(line.IndexOf('|')));
Full code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
static class Program
{
static void Main()
{
var qry = (from line in ReadLines("foo.txt")
let parts = line.Split('|')
select new
{
Line = line,
Key = new
{
A = parts[1].Trim(),
B = parts[2].Trim(),
C = parts[3].Trim()
}
}).DistinctBy(row => row.Key)
.Select(row => row.Line);
foreach (var line in qry)
{
Console.WriteLine(line);
}
}
static IEnumerable<TSource> DistinctBy<TSource, TValue>(
this IEnumerable<TSource> source,
Func<TSource, TValue> selector)
{
var found = new HashSet<TValue>();
foreach (var item in source)
{
if (found.Add(selector(item))) yield return item;
}
}
static IEnumerable<string> ReadLines(string path)
{
using (var reader = File.OpenText(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
}
Check out this, this will do what you want to do
static void Main(string[] args)
{
string[] readfile = System.IO.File.ReadAllLines(#"D:\1.txt");
var strList = readfile.Select(x => x.Split('|')).ToList();
IEnumerable<string[]> noduplicates =strList.Distinct(new StringComparer());
foreach (var res in noduplicates)
Console.WriteLine(res[0] + "|" + res[1] + "|" + res[2] + "|" + res[3]);
}
And implement the IEqualityComparer this way
class StringComparer : IEqualityComparer<string[]>
{
public bool Equals(string[] x, string[] y)
{
if (Object.ReferenceEquals(x, y)) return true;
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
return x[1].Trim() == y[1].Trim() && x[2].Trim() == y[2].Trim() && x[3].Trim() == y[3].Trim() ;
}
public int GetHashCode(string[] data)
{
if (Object.ReferenceEquals(data, null)) return 0;
int hash1 = data[1] == null ? 0 : data[1].Trim().GetHashCode();
int hash2 = data[2] == null ? 0 : data[2].Trim().GetHashCode();
int hash3 = data[3] == null ? 0 : data[3].Trim().GetHashCode();
return hash1 ^ hash2 * hash3;
}
}
It will give u the output as you expected.
Related
Currently using:
ASP.NET Core 3.1 / EF Core
C#
Code-first approach
Postgres database
I'm building a method to support column searching on a table. I need to feed the column name to be searched by string value and build a query / lambda that can search the right column. I suspect I need to build some sort of expression and search on the expression but am having trouble with the syntax.
Here's the base code:
string search = "Search Value";
string givenColumn = "search_column";
IQueryable<MyModel> data = _dbContext.table;
data = data.Where(data => data.givenColumn.Contains(search));
I'd like to feed the column name in givenColumn and be able to build a query that searches the right column. At first I thought I wanted reflection but I'm looking to build a SQL query based off of a string, so I think I want to build an expression?
TIA!
Here is some sample code for a runtime WhereContains that operates on string columns:
public static class IQueryableExt {
// String.Contains(string)
static MethodInfo containsMI = typeof(string).GetMethod("Contains", 0, new[] { typeof(string) });
// generate r => r.{columnname}.Contains(value)
static Expression<Func<T, bool>> WhereContainsExpr<T>(string columnname, string value) {
// (T r)
var rParm = Expression.Parameter(typeof(T), "r");
// r.{columnname}
var rColExpr = Expression.Property(rParm, columnname);
// r.{columnname}.Contains(value)
var bodyExpr = Expression.Call(rColExpr, containsMI, Expression.Constant(value));
return Expression.Lambda<Func<T,bool>>(bodyExpr, rParm);
}
public static IQueryable<T> WhereContains<T>(this IQueryable<T> src, string columname, string value) => src.Where(WhereContainsExpr<T>(columname, value));
}
Just pass HTML Table id as a parameter onkeyup method of input field. HTML Code:
<input type="text" id="myInput" class="form-control search-input" onkeyup="searchData('myTable')" placeholder="Search...">
Javascript Code for exact match of any column:
function searchData(tableId) {
// Declare variables
var input, filter, table, tr, i, j, column_length, count_td;
column_length = document.getElementById(tableId).rows[0].cells.length;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById(tableId);
tr = table.getElementsByTagName("tr");
if (filter != "") {
for (i = 1; i < tr.length; i++) { // except first(heading) row
count_td = 0;
for (j = 1; j < column_length - 1; j++) { // except first column
td = tr[i].getElementsByTagName("td")[j];
/* ADD columns here that you want you to filter to be used on */
if (td) {
if (td.innerHTML.toUpperCase() === filter) {
count_td++;
}
}
}
if (count_td > 0) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
else {
for (i = 1; i < tr.length; i++) {
tr[i].style.display = "";
}
}
}
I'm trying to de-dupe an array of objects using two columns where the second column is a Dictionary. Best way to describe this is to show some code:
class MyClass
{
public int ID;
public Dictionary<int, int> Dict = new Dictionary<int, int>();
}
And now to create some objects:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
What I'm looking to accomplish is to distinct by ID and Dict. The results should look like this:
List of MyClass objects (not pretty)
1 //MyClass.ID
1,1 //MyClass.Dictionary
1
1,2
2
1,1
Notice that one of the objects was dropped from the original list because it had a duplicate ID and Dict (dictionary values). I've been playing around with alternate versions of:
var s = from p in list
group p by p.ID into group1
from group2 in
(from p in group1 group p by p.Dict)
group group2 by group1.Key;
but just haven't had any luck. Appreciate any insight folks might have on solving this problem.
PS - I'm not changing the rules but I believe a GROUP BY and a SELECTFIRST will be cleaner than a DISTINCT with its extra code for a Comparer. A pat on the back for anyone who can figure this out using GROUP BY.
For reference types you should add equality comparer in order to do what you want. Add the following class:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass left, MyClass right)
{
if (left == null && right == null)
{
return true;
}
if (left == null || right == null)
{
return false;
}
if (left.ID == right.ID)
{
if (left.Dict == null && right.Dict == null)
{
return true;
}
if (left.Dict == null || right.Dict == null)
{
return false;
}
if (left.Dict.Count != right.Dict.Count)
{
return false;
}
foreach(var key in left.Dict.Keys)
{
if(!right.Dict.ContainsKey(key))
return false;
if (left.Dict[key] != right.Dict[key])
return false;
}
return true;
}
else return false;
}
public int GetHashCode(MyClass author)
{
return (author.ID).GetHashCode();
}
}
And use that comparer in Distinct override:
List<MyClass> list = new List<MyClass>();
MyClass mc1 = new MyClass();
list.Add(mc1); mc1.ID = 1; mc1.Dict.Add(1, 1);
MyClass mc2 = new MyClass();
list.Add(mc2); mc2.ID = 1; mc2.Dict.Add(1, 1);
MyClass mc3 = new MyClass();
list.Add(mc3); mc3.ID = 1; mc3.Dict.Add(1, 2);
MyClass mc4 = new MyClass();
list.Add(mc4); mc4.ID = 2; mc4.Dict.Add(1, 1);
var result = list.Distinct(new MyClassComparer()).ToList();
You should improve GetHashCode method. It will be your homework :)
Can I have half a pat for the following ? :)
var filteredList = list.GroupBy(mc => mc.ID)
.SelectMany(gr => gr.Distinct(new MyClassComparer()))
.ToList();
Comparer:
public class MyClassComparer : IEqualityComparer<MyClass>
{
public bool Equals(MyClass a, MyClass b)
{
return a.Dict.Count == b.Dict.Count && !a.Dict.Except(b.Dict).Any();
}
public int GetHashCode(MyClass a)
{
return a.ID;
}
}
I have a repository with this method
public virtual IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>,
IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "");
I have a method that is using it as such to get a user to work on
var user = this.applicationUserRepository.Get(x => x.EmailAddress == userName).FirstOrDefault();
It then calls the same method with a different expression further in the method as follows to check the user working on the first user
var changingUser = this.applicationUserRepository.Get(x => x.Id == changingUserId).FirstOrDefault();
I am trying to mock the repository with two setups to call it twice in the same test.
string emailAddress = "myaddresss#test.com";
int changingUserId = 5;
var targetUsers = new List<ApplicationUser>
{
new ApplicationUser { Id = 1, Password = "Testing123", EmailAddress = emailAddress }
};
// Setup the user that will be modified to be found
var mockApplicationUserRepository = new Mock<IRepository<ApplicationUser>>();
mockApplicationUserRepository
.Setup(aur => aur.Get(x => x.EmailAddress == userName, null, string.Empty))
.Returns(targetUsers.AsEnumerable());
// Set up to query the changing user to not be found
mockApplicationUserRepository
.Setup(aur2 => aur2.Get(x => x.Id == changingUserId, null, string.Empty))
.Returns(new List<ApplicationUser>().AsEnumerable()); // Empty list
Even though the second call will never be hit, for this test, I want to learn how to set this up.
When I run the test the first call
var user = this.applicationUserRepository.Get(x => x.EmailAddress == userName).FirstOrDefault();
I get null
If I change the mock to have
It.IsAny<Expression<Func<ApplicationUser, bool>>>()
I get the expected user back.
I can not figure out how I will set the two calls up so it will know which expression to use. Any help will be appreciated.
The problem is that Moq does not compare the expressions you use (only reference equality).
Using this little helper class:
public static class LambdaCompare
{
public static bool Eq<TSource, TValue>(
Expression<Func<TSource, TValue>> x,
Expression<Func<TSource, TValue>> y)
{
return ExpressionsEqual(x, y, null, null);
}
public static Expression<Func<Expression<Func<TSource, TValue>>, bool>> Eq<TSource, TValue>(Expression<Func<TSource, TValue>> y)
{
return x => ExpressionsEqual(x, y, null, null);
}
private static bool ExpressionsEqual(Expression x, Expression y, LambdaExpression rootX, LambdaExpression rootY)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
var valueX = TryCalculateConstant(x);
var valueY = TryCalculateConstant(y);
if (valueX.IsDefined && valueY.IsDefined)
return ValuesEqual(valueX.Value, valueY.Value);
if (x.NodeType != y.NodeType
|| x.Type != y.Type) return false;
if (x is LambdaExpression)
{
var lx = (LambdaExpression) x;
var ly = (LambdaExpression) y;
var paramsX = lx.Parameters;
var paramsY = ly.Parameters;
return CollectionsEqual(paramsX, paramsY, lx, ly) && ExpressionsEqual(lx.Body, ly.Body, lx, ly);
}
if (x is MemberExpression)
{
var mex = (MemberExpression) x;
var mey = (MemberExpression) y;
return Equals(mex.Member, mey.Member) && ExpressionsEqual(mex.Expression, mey.Expression, rootX, rootY);
}
if (x is BinaryExpression)
{
var bx = (BinaryExpression) x;
var by = (BinaryExpression) y;
return bx.Method == #by.Method && ExpressionsEqual(bx.Left, #by.Left, rootX, rootY) &&
ExpressionsEqual(bx.Right, #by.Right, rootX, rootY);
}
if (x is ParameterExpression)
{
var px = (ParameterExpression) x;
var py = (ParameterExpression) y;
return rootX.Parameters.IndexOf(px) == rootY.Parameters.IndexOf(py);
}
if (x is MethodCallExpression)
{
var cx = (MethodCallExpression)x;
var cy = (MethodCallExpression)y;
return cx.Method == cy.Method
&& ExpressionsEqual(cx.Object, cy.Object, rootX, rootY)
&& CollectionsEqual(cx.Arguments, cy.Arguments, rootX, rootY);
}
throw new NotImplementedException(x.ToString());
}
private static bool ValuesEqual(object x, object y)
{
if (ReferenceEquals(x, y))
return true;
if (x is ICollection && y is ICollection)
return CollectionsEqual((ICollection) x, (ICollection) y);
return Equals(x, y);
}
private static ConstantValue TryCalculateConstant(Expression e)
{
if (e is ConstantExpression)
return new ConstantValue(true, ((ConstantExpression) e).Value);
if (e is MemberExpression)
{
var me = (MemberExpression) e;
var parentValue = TryCalculateConstant(me.Expression);
if (parentValue.IsDefined)
{
var result =
me.Member is FieldInfo
? ((FieldInfo) me.Member).GetValue(parentValue.Value)
: ((PropertyInfo) me.Member).GetValue(parentValue.Value);
return new ConstantValue(true, result);
}
}
if (e is NewArrayExpression)
{
var ae = ((NewArrayExpression) e);
var result = ae.Expressions.Select(TryCalculateConstant);
if (result.All(i => i.IsDefined))
return new ConstantValue(true, result.Select(i => i.Value).ToArray());
}
return default(ConstantValue);
}
private static bool CollectionsEqual(IEnumerable<Expression> x, IEnumerable<Expression> y, LambdaExpression rootX, LambdaExpression rootY)
{
return x.Count() == y.Count()
&& x.Select((e, i) => new {Expr = e, Index = i})
.Join(y.Select((e, i) => new { Expr = e, Index = i }),
o => o.Index, o => o.Index, (xe, ye) => new { X = xe.Expr, Y = ye.Expr })
.All(o => ExpressionsEqual(o.X, o.Y, rootX, rootY));
}
private static bool CollectionsEqual(ICollection x, ICollection y)
{
return x.Count == y.Count
&& x.Cast<object>().Select((e, i) => new { Expr = e, Index = i })
.Join(y.Cast<object>().Select((e, i) => new { Expr = e, Index = i }),
o => o.Index, o => o.Index, (xe, ye) => new { X = xe.Expr, Y = ye.Expr })
.All(o => Equals(o.X, o.Y));
}
private struct ConstantValue
{
public ConstantValue(bool isDefined, object value) : this()
{
IsDefined = isDefined;
Value = value;
}
public bool IsDefined { get; private set; }
public object Value { get; private set; }
}
}
you can setup your mock like this:
Expression<Func<ApplicationUser, bool>> expr = x => x.EmailAddress == emailAddress;
var mockApplicationUserRepository = new Mock<IRepository<ApplicationUser>>();
mockApplicationUserRepository
.Setup(aur => aur.Get(It.Is<Expression<Func<ApplicationUser, bool>>>(x => LambdaCompare.Eq(x, expr)), null, string.Empty))
.Returns(targetUsers.AsEnumerable());
Just adding a comment to this old answer (though quite useful code)
This version of LambdaCompare class is missing a case to compare an UnaryExpression, something which is included in the code in the original post.
Use that code instead of this (I learnt the hard way...)
Im trying to write a method which will allow me to search different DataTables, over different columns.
So far i have the following:
string selectedValue;
string searchColumn;
string targetColumn;
var results = (from a in dt.AsEnumerable()
where a.Field<string>(searchColumn) == selectedValue
select new
{
targetColumn = a.Field<string>(targetColumn)
}).Distinct();
Which kind of gets the job done, but I'm left with the column name as targetColumn rather than the actual column name I want.
Is there any way to resolve this?
Thanks in advance
CM
I make a LINQ to Datatables
public List<DataRow> Where(this DataTable dt, Func<DataRow, bool> pred)
{
List<DataRow> res = new List<DataRow>();
try {
if (dt != null && dt.Rows.Count > 0) {
for (i = 0; i <= dt.Rows.Count - 1; i++) {
if (pred(dt(i))) {
res.Add(dt(i));
}
}
}
} catch (Exception ex) {
PromptMsg(ex);
}
return res;
}
Usage :
var RowsList = dt.Where(f => f("SomeField").toString() == "SomeValue" ||
f("OtherField") > 5);
I need to consider multiple conditions to get value.
i mean if all conditions true that must give me a filtered answer.
Or one of them is true,rest are false...
so i need to write all possibilities??
if(a&b&c&d) else if(a&b&c) else if(a&c&d) else if(b&c&d) else if(a&b) else if (a&c)...etc ?? :))) Is there a shorter way to do this?
public List<ProductReqNoDate> GetRequestsQuery(string departmant, int reqStateID, string firstDate, string lastDate, string productName)
{
var db = new requestDBEntities();
bool dp = !string.IsNullOrEmpty(departmant);
bool pr = !string.IsNullOrEmpty(productName);
bool tm = !string.IsNullOrEmpty(firstDate) && !string.IsNullOrEmpty(lastDate);
bool rs = reqStateID > 0 ? true : false;
var query = (from r in db.requests
select new ProductReqNoDate
{
departmant = r.departmant,
reqNo = r.reqNo,
reqDate = r.reqDate,
productName = (from p in db.products where p.reqNo == r.reqNo select p.productName).FirstOrDefault()
}).ToList();
if (dp & pr & tm & rs)
{
var rState = (from ta in db.reqStates
where ta.reqStateID == reqStateID && ta.isActive == true
select ta.reqNo).ToList();
var prName = (from p in db.products where p.productName.Contains(productName) select p.reqNo).ToList();
DateTime dtfirstDate = Convert.ToDateTime(firstDate);
DateTime dtlastDate = Convert.ToDateTime(lastDate);
return query.Where(
r => rState.Contains(r.reqNo) //find by Request State
&& r.departmant == departmant //find by Departmant
&& (r.reqDate >= dtfirstDate && r.reqDate <= dtlastDate) //find by Date
&& prName.Contains(r.reqNo) //Find By Product Name
).ToList();
}
else if (dp & pr & tm) { /*return query.Where(...} */}
else if (pr & tm & rs) { /*return query.Where(...} */}
else if (dp & pr && rs) { /*return query.Where(...} */}
else if (dp & pr) { /*return query.Where(...} */}
//else if ...etc
}
Just add one Where condition at a time
public List<ProductReqNoDate> GetRequestsQuery(string departmant, int reqStateID, string firstDate, string lastDate, string productName)
{
var db = new requestDBEntities();
bool dp = !string.IsNullOrEmpty(departmant);
bool pr = !string.IsNullOrEmpty(productName);
bool tm = !string.IsNullOrEmpty(firstDate) && !string.IsNullOrEmpty(lastDate);
bool rs = reqStateID > 0 ? true : false;
var query = (from r in db.requests
select new ProductReqNoDate
{
departmant = r.departmant,
reqNo = r.reqNo,
reqDate = r.reqDate,
productName = (from p in db.products where p.reqNo == r.reqNo select p.productName).FirstOrDefault()
}).AsQueryable(); //AsQueryable is not always needed, but it shouldn't hurt and I don't feel like checking for this example.
if (dp)
{
query = query.Where(q => /*condition*/);
}
if (pr)
{
query = query.Where(q => /*condition*/);
}
if (tm)
{
query = query.Where(q => /*condition*/);
}
if (rs)
{
query = query.Where(q => /*condition*/);
}
return query.ToList();
}
You can build an expression with Expression.And like:
private Expression<Func<Request, bool>> GetPredicate(FilterDto filter)
{
Expression<Func<Request, bool>> predicate = r => r.ID == r.ID;
if (filter.Department.HasValue)
predicate = predicate.And(r => r.Department == filter.Department.Value);
if (filter.FirstDate.HasValue)
predicate = predicate.And(r => (r.reqDate >= filter.FirstDate.Value));
if (filter.LastDate.HasValue)
predicate = predicate.And(r => (r.reqDate <= filter.LastDate.Value));
/* ... */
return predicate;
}
Note: I put r => r.ID == r.ID here as first expression, just to have an expression to start with. This snippet does not fully cover your code, but I think it is enough as an example.
Use the expression in return query.Where(expression).ToList().