Using C# with Lambda(or some method), how can I merge different informations(from columns) of the same intituition name ? They can have some common and some different fields.
See a example below:
Have you tried the Group By instruction ?
Here is an other stackoverflow about this : Group by in LINQ
{
List<Instituition> Instituitions = new List<Instituition>() {
new Instituition { Name = "Name1", Alias = "",Area="" },
new Instituition { Name = "Name1", Alias = "Alias1",Area="" },
new Instituition { Name = "name2", Alias = "Audi" ,Area="444"},
new Instituition { Name = "Name1", Alias = "",Area="Garden" }};
var results = Instituitions.GroupBy(i => i.Name,
i => i.Alias,
(key, g) => new
{
Name = key,
Alias = g.Where(a =>a != "").FirstOrDefault(),
Area = Instituitions.Where(a=>a.Name == key && a.Area != "").Select(a=>a.Area).FirstOrDefault()
}
);
}
class Instituition
{
internal string Name;
internal string Alias;
internal string Area;
}
Related
I want to return the List of records with Id and name, where the name will be appended with the domain as name(domain) if the names are non-unique and it will again append with code if domain is also non-unique, such as name(domain)(code).
To be Clear
name - for unique names,
name(domain) - for duplicated names
name(domain)(code) - for duplicated codes.
Below are the sample data and expected data
**Sample Data**
var filter = new List<Record>()
{
new Record { Id = 011, Name = "OAKLAWN", Code = 123, Domain = "p1000"},
new Record { Id = 012, Name = "OAKLAWN", Code = 124 , Domain = "p2000"},
new Record { Id = 013, Name = "OAKLAWN", Code = 125 , Domain = "p3000"},
new Record { Id = 014, Name = "OAKLAWN", Code = 126 , Domain = "p4000"},
new Record { Id = 015, Name = "OAKLAWN", Code = 127 , Domain = "p5000"},
new Record { Id = 016, Name = "PEAKLAWN", Code = 111 , Domain = "p6000"},
new Record { Id = 017, Name = "PERKLAWN", Code = 124 , Domain = "p6000"},
new Record { Id = 018, Name = "QUCKLAWN", Code = 122 , Domain = "p6000"}
};
**expected return data**
{ Id = 011, Name = "OAKLAWN(p1000)"},
{ Id = 012, Name = "OAKLAWN(p2000)(124)"},
{ Id = 013, Name = "OAKLAWN(p3000)"},
{ Id = 014, Name = "OAKLAWN(p2000)(126)"},
{ Id = 015, Name = "OAKLAWN(p5000)"},
{ Id = 016, Name = "PEAKLAWN"},
{ Id = 017, Name = "PERKLAWN"},
{ Id = 018, Name = "QUCKLAWN"}
How can I achieve this using c# LINQ.
.NET fiddle: https://dotnetfiddle.net/2UdaxY
Thanks.
var records = filter.GroupBy(
r => r.Name,
(key, group) => group.Select(r => new
{
r.Id,
Name = group.Count() == 1
? key
: group.Count(x => x.Domain == r.Domain) == 1
? $"{key}({r.Domain})"
: $"{key}({r.Domain})({r.Code})"
})
)
.SelectMany(r => r)
.ToArray();
.NET fiddle: https://dotnetfiddle.net/tIPZOR
Querying a table on Secondary Index, using a BeginsWith Operator does not always return the correct records. What could be the reason for that?
I have sample Code and tried it against a local DynamoDB table and against a table in AWS. The results are the same.
Defining the secondary index:
var gsiKey1Index = new GlobalSecondaryIndex
{
IndexName = "GSIKey1Index",
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 1,
WriteCapacityUnits = 1
},
Projection = new Projection { ProjectionType = "ALL" }
};
var indexKey1Schema = new List<KeySchemaElement> {
{
new KeySchemaElement
{
AttributeName = "HashKey", KeyType = KeyType.HASH
}
}, //Partition key
{
new KeySchemaElement
{
AttributeName = "GSISortKey1", KeyType = KeyType.RANGE
}
} //Sort key
};
gsiKey1Index.KeySchema = indexKey1Schema;
Creating the table:
var request = new CreateTableRequest
{
TableName = "TestTable",
AttributeDefinitions = new List<AttributeDefinition>
{
new AttributeDefinition
{
AttributeName = "HashKey",
// "S" = string, "N" = number, and so on.
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "SortKey",
AttributeType = "S"
},
new AttributeDefinition
{
AttributeName = "GSISortKey1",
// "S" = string, "N" = number, and so on.
AttributeType = "S"
},
},
KeySchema = new List<KeySchemaElement>
{
new KeySchemaElement
{
AttributeName = "HashKey",
// "HASH" = hash key, "RANGE" = range key.
KeyType = "HASH"
},
new KeySchemaElement
{
AttributeName = "SortKey",
KeyType = "RANGE"
},
},
GlobalSecondaryIndexes = { gsiKey1Index },
ProvisionedThroughput = new ProvisionedThroughput
{
ReadCapacityUnits = 10,
WriteCapacityUnits = 5
},
};
response2 = await _client.CreateTableAsync(request);
The Entity looks like this:
[DynamoDBTable("TestTable")]
public sealed class TestResult
{
[DynamoDBHashKey]
public string HashKey {get;set;}
public string SortKey {get;set;}
public string GSISortKey1 {get; set;}
}
The code to query looks like this:
public async Task<List<TestResult>> GetTestResultByDateTimeAsync(Guid hashid, Guid someId, string someName, DateTime timestamp)
{
var key2 = $"TR-{someId}-{someName}-{timestamp:yyyy-MM-ddTHH\\:mm\\:ss.fffZ}";
var key = $"TR-{someId}-{someName}-{timestamp:yyyy-MM-dd}";
//var filter = new QueryFilter();
//filter.AddCondition("HashKey", ScanOperator.Equal, hashid.ToString());
//filter.AddCondition("GSISortKey1", ScanOperator.BeginsWith, key);
//var queryConfig = new QueryOperationConfig
//{
// Filter = filter
//};
DynamoDBOperationConfig operationConfig = new DynamoDBOperationConfig()
{
OverrideTableName = "DEVTransponderTR",
IndexName = "GSIKey1Index",
QueryFilter = new List<ScanCondition>()
};
var sc = new ScanCondition("GSISortKey1", ScanOperator.BeginsWith, new[] { key });
operationConfig.QueryFilter.Add(sc);
var search = _context.QueryAsync<TestResult>(tenantid.ToString(), operationConfig);
var testresults = await search.GetRemainingAsync();
bool keywasok = true;
foreach (var testresult in testresults)
{
keywasok = testresult.GSISortKey1.StartsWith(key2) && keywasok;
}
if (keywasok) // this means I should find the same values if I use key2
{
DynamoDBOperationConfig operationConfig2 = new DynamoDBOperationConfig()
{
OverrideTableName = "TestTable",
IndexName = "GSIKey1Index",
QueryFilter = new List<ScanCondition>()
};
var sc2 = new ScanCondition("GSISortKey1", ScanOperator.BeginsWith, new[] { key2 });
operationConfig2.QueryFilter.Add(sc2);
var search2 = _context.QueryAsync<TestResult>(tenantid.ToString(), operationConfig);
var testresults2 = await search.GetRemainingAsync();
}
return testresults;
}
Then I add three instances to the table. importants is that all information is the same except the GSISortKey1 value. This is the GSISortKey1 value for the three items:
"TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-Open"
"TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-Send"
"TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-Test"
So in the example I first query on "BeginsWith" with a value of "TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02" (this is var key)
It returns all three items.
Then I check if the whole GSISortKey1 value of three returned items would also begin with the value "TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-", and that is true.
If that is true I just query again with a BeginsWith using the value "TR-0d798900-a852-4a75-bef0-5dd5c96c657c-Module1-2019-04-02T12:24:19.000Z-"
It should return all three items. it returns 0 items.
I guess I am doing something wrong, some help appreciated.
I have two functions, returning expression translated to EF.:
public static Expression<Func<TripLanguage, TripViewModel>> ToSearchModel(ILookup<int, TagViewModel> tags)
{
return tripLanguage => new TripViewModel()
{
From = tripLanguage.From,
To = tripLanguage.To,
Annotation = tripLanguage.Description.Truncate(Strings.TRUNCATE_ANOTATION),
Level = tripLanguage.Trip.Level,
BicycleType = tripLanguage.Trip.BicycleType,
UrlId = tripLanguage.UrlId,
Distance = tripLanguage.Trip.Distance,
Tags = tags[tripLanguage.TripId], //This is only different and in function args of course
MainImage = tripLanguage.Trip.Images.OrderBy(s => s.Date).Select(i => new ImageViewModel
{
Filename = i.Filename,
Id = i.Id,
Title = i.Title
}).Take(1)
};
}
public static Expression<Func<TripLanguage, TripViewModel>> ToSearchModel()
{
return tripLanguage => new TripViewModel()
{
From = tripLanguage.From,
To = tripLanguage.To,
Annotation = tripLanguage.Description.Truncate(Strings.TRUNCATE_ANOTATION),
Level = tripLanguage.Trip.Level,
BicycleType = tripLanguage.Trip.BicycleType,
UrlId = tripLanguage.UrlId,
Distance = tripLanguage.Trip.Distance,
MainImage = tripLanguage.Trip.Images.OrderBy(s => s.Date).Select(i => new ImageViewModel
{
Filename = i.Filename,
Id = i.Id,
Title = i.Title
}).Take(1)
};
}
The only different is Tags collection. Is possible something like call method, without arguments and add Tags attribute which exclude duplicate code? Or Use some inheritance expression?
Thank you for your time.
Change the first method to work with null tags, and provide a null default for it:
public static Expression<Func<TripLanguage,TripViewModel>> ToSearchModel(ILookup<int, TagViewModel> tags = null) {
return tripLanguage => new TripViewModel() {
From = tripLanguage.From,
To = tripLanguage.To,
Annotation = tripLanguage.Description.Truncate(Strings.TRUNCATE_ANOTATION),
Level = tripLanguage.Trip.Level,
BicycleType = tripLanguage.Trip.BicycleType,
UrlId = tripLanguage.UrlId,
Distance = tripLanguage.Trip.Distance,
Tags = tags?[tripLanguage.TripId], // <<== Note the question mark
MainImage = tripLanguage.Trip.Images.OrderBy(s => s.Date).Select(i => new ImageViewModel
{
Filename = i.Filename,
Id = i.Id,
Title = i.Title
}).Take(1)
};
}
public class Foo
{
public ObjectId _id { get; set; }
public BsonDocument properties { get; set; }
}
public void FindFoos()
{
var client = new MongoClient(ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
var server = client.GetServer();
var db = server.GetDatabase("FooBar");
//var collection = db.GetCollection<GeoJsonFeature<GeoJson2DGeographicCoordinates>>("Sections");
var collection = db.GetCollection<Foo>("Foos");
collection.Insert(new Foo
{
properties = new BsonDocument{
{"Foo" , "foo1"},
{"Bar" , "bar1"}
}
});
collection.Insert(new Foo
{
properties = new BsonDocument{
{"Foo" , "foo2"},
{"Bar" , "bar2"}
}
});
var query = Query<Foo>.Where(foo => foo.properties.AsQueryable().Any(property => property.Name == "Foo" && property.Value.AsString == "foo1"));
var result = collection.Find(query).First();
}
calling FindFoos results in the following exception:
Unsupported where clause: Queryable.Any(Queryable.AsQueryable(foo.properties), (BsonElement property) => ((property.Name == "Foo") && (property.Value.AsString == "foo1"))).
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: Unsupported where clause: Queryable.Any(Queryable.AsQueryable(foo.properties), (BsonElement property) => ((property.Name == "Foo") && (property.Value.AsString == "foo1"))).
at the line:
var query = Query<Foo>.Where(foo => foo.properties.AsQueryable().Any(property => property.Name == "Foo" && property.Value.AsString == "foo1"));
I can do this query easily in the mongodb shell as:
db.Foos.find( {'properties.Foo' : 'foo1'} );
What is the correct way to do this query with Linq?
Try LINQ's SelectMany() method. It is used to flatten nested collections. Instead of using nested for loops, we can do the task in a more 'LINQ' way.
Ex given below -
Master m1 = new Master() { name = "A", lstObj = new List<obj> { new obj { i = 1, s = "C++" }, new obj { i = 1, s = "C#" }, new obj { i = 1, s = "Java" } } };
Master m2 = new Master() { name = "A", lstObj = new List<obj> { new obj { i = 4, s = "PHP" }, new obj { i = 5, s = "Ruby" }, new obj { i = 6, s = "Perl" } } };
List<Master> lstMasters = new List<Master> { m1, m2 };
var result = lstMasters.SelectMany(m => m.lstObj).Where(o => o.s == "PHP");
Just replace the Master class with your BsonDocument.
var setsA = new List<SetA> {
new SetA { SsnA = "3450734507", name = "setA"},
new SetA { SsnA = "6833467788", name = "setA"},
new SetA { SsnA = "5452347787", name = "setA"},
new SetA { SsnA = "9345345345", name = "setA"},
};
var setsB = new List<SetB> {
new SetB { SsnB = "5452347787" ,name = "setB"},
new SetB { SsnB = "9345345345", name = "setB"},
};
when i use this linq:
var Set =
from seta in setsA
join setb in setsB
on seta.SsnA
equals setb.SsnB
select new {
SSN = seta.SsnA,
NAME = setb.name
};
i get this value:
{ SSN = "5452347787", NAME = "setB" }
{ SSN = "9345345345", NAME = "setB" }
but i would want to have SET which combines these two and the result would be:
{ SSN = "3450734507", NAME = "setA" }
{ SSN = "6833467788", NAME = "setA" }
{ SSN = "5452347787", NAME = "setB" }
{ SSN = "9345345345", NAME = "setB" }
This would be a result set that would tell me with the name NAME property which set it was taken from, if SSN was found in SetA and SetB it would have property NAME = "setB"
could someone help me with this?
It seems you want an outer join - this is done using GroupJoin:
var set = setsA.GroupJoin(
setsB,
sa => sa.SsnA,
sb => sb.SsnB,
(a, bs) => new { SSN = a.SsnA, NAME = bs.Any() ? "setB" : "setA" });
The LINQ way described here:
http://msdn.microsoft.com/en-us/library/bb397895.aspx would look like this (functionally same to the lambda way):
var set = from a in setsA
join b in setsB on a.SsnA equals b.SsnB into g
from o in g.DefaultIfEmpty()
select new { SSN = a.SsnA, NAME = (o != null ? o.name : a.name)};