LINQ. ordered list by key group but first group are with condition [duplicate] - c#

This question already has answers here:
Linq Order by a specific number first then show all rest in order
(6 answers)
Closed yesterday.
I"m have List ordered by key group.
var productList = CustomerData.Data.Products
.GroupBy(x => x.CategoryDesc)
.OrderBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.ToList());
it's good working
And i want one SPECIFIC group (with sale) set as first in the list.
But the rest of the groups to stay sorted in descending order.
something like that:
***I wrote in the format for the convenience of seeing
[
{
"Key": "SPECIFIC",
"Value": [
{
"SubGroup": "wire cutters",
"Model": "A",
"Price": "65"
},
{
"SubGroup": "hammers",
"Model": "B",
"Price": "71"
},
{
"SubGroup": "hammers",
"Model": "C",
"Price": "92.5"
},
]
},
{
"Key": "Rank A",
"Value": [
{
"SubGroup": "hammers",
"Model": "A",
"Price": "130"
},
{
"SubGroup": "hammers",
"Model": "B",
"Price": "142"
},
{
"SubGroup": "hammers",
"Model": "C",
"Price": "185"
},
]
},
{
"Key": "Rank B",
"Value": [
{
"SubGroup": "pliers",
"Model": "A",
"Price": "95"
},
{
"SubGroup": "pliers",
"Model": "B",
"Price": "59"
},
{
"SubGroup": "pliers",
"Model": "C",
"Price": "65"
},
]
},
{
"Key": "Rank C",
"Value": [
{
"SubGroup": "saws",
"Model": "A",
"Price": "905"
},
{
"SubGroup": "saws",
"Model": "B",
"Price": "589"
},
{
"SubGroup": "saws",
"Model": "C",
"Price": "655"
},
]
},
]

Add additional Order. First for detecting specific items, ThenBy for the rest.
var productList = CustomerData.Data.Products
.GroupBy(x => x.CategoryDesc)
.OrderByDescending(x => x.Key == "SPECIFIC")
.ThenBy(x => x.Key)
.ToDictionary(x => x.Key, x => x.ToList());

Related

How to only return specific object list base on the condition

I want to add a condition to for returning selected object list. If the condition is met, it will not return the an item if its category is for this example, category is 3.
This is the query:
var objectQuery = query
.ToList()
.Select(a => new
{
a.Id,
ObjectDetails = (new ObjectClass[] { })
.Concat(...)
.Concat(...)
.Distinct()
.Select(f => new
{
f.ObjectDetails.Id,
f.ObjectDetails.Name,
f.ObjectDetails.DisplayName,
category = (int)f.ObjectDetails.Category,
f.ObjectDetails.IsArchived,
})
});
return objectQuery.ToList().FirstOrDefault();
i want to add a condition like this where if it met the condition, it will remove all items with category 3 and returns all the item if not, but i dont know how to properly implement it:
if(condition a)
return objectQuery.Select(...Where(category != 3)).ToList().FirstOrDefault();
else
return objectQuery.ToList().FirstOrDefault();
this is the return output:
{
"objectQuery": {
"id": 1198,
"ObjectDetails": [
{
"id": 1,
"name": "name one",
"displayName": "NAME 1",
"Category": 1,
},
{
"id": 2,
"name": "name two",
"displayName": "NAME 2",
"Category": 1,
},
{
"id": 3,
"name": "name three",
"displayName": "NAME 3",
"Category": 2,
},
{
"id": 4,
"name": "name four",
"displayName": "NAME 4",
"Category": 2,
},
{
"id": 5,
"name": "name five",
"displayName": "NAME 5",
"Category": 3,
},
{
"id": 6,
"name": "name six",
"displayName": "NAME 6",
"Category": 1,
},
{
"id": 7,
"name": "name seven",
"displayName": "NAME 7",
"Category": 1,
}
]
}
}
If I get your question properly then you'll need something like this:
var objectQuery = query
.ToList()
.Select(a => new
{
a.Id,
ObjectDetails = (new ObjectClass[] { })
.Concat(...)
.Concat(...)
.Distinct()
.Select(f => new
{
f.ObjectDetails.Id,
f.ObjectDetails.Name,
f.ObjectDetails.DisplayName,
category = (int)f.ObjectDetails.Category,
f.ObjectDetails.IsArchived,
})
.Where(f => !condition || f.category != 3)
});
return objectQuery.ToList().FirstOrDefault();

Retrieving list of documents from collection by id in nested list

I have documents like this:
[
// 1
{
"_id": ObjectId("573f3944a75c951d4d6aa65e"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Japan",
}
]
}
]
},
// 2
{
"_id": ObjectId("573f3d41a75c951d4d6aa65f"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "USA"
}
]
}
]
},
// 3
{
"_id": ObjectId("573f4367a75c951d4d6aa660"),
"Source": "NRK",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Germany"
}
]
}
]
},
// 4
{
"_id": ObjectId("573f4571a75c951d4d6aa661"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 10,
"name": "France"
}
]
}
]
},
// 5
{
"_id": ObjectId("573f468da75c951d4d6aa662"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 14,
"name": "England"
}
]
}
]
}
]
I want to return only the documents with source equals 'Countries.uid' equal 17
so I have in the end :
[
{
"_id": ObjectId("573f3944a75c951d4d6aa65e"),
"Source": "IGN",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Japan",
}
]
}
]
},
{
"_id": ObjectId("573f3d41a75c951d4d6aa65f"),
"Source": "VG",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "USA"
}
]
}
]
},
{
"_id": ObjectId("573f4367a75c951d4d6aa660"),
"Source": "NRK",
"Family": [
{
"Countries": [
{
"uid": 17,
"name": "Germany"
}
]
}
]
}
]
How can I do this with the official C# MongoDB driver?
Tried this :
public List<Example> getLinkedCountry(string porduitId)
{
var filter = Builders<Example>.Filter.AnyIn("Family.Countries.uid", porduitId);
var cursor = await _certificats.FindAsync(filter);
var docs = cursor.ToList();
return docs;
}
Unfortunately, I think my filter is wrong.
Is there a way to find all the documents by accessing the nested list by id and retrieving it?
Solution 1
Use ElemMatch instead of AnyIn.
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
Output
Solution 2
If you are unconfident with MongoDB .Net Driver syntax, you can convert the query as BsonDocument via MongoDB Compass (Export to language feature).
var filter = new BsonDocument("Family.Countries.uid", porduitId);
Just to expand on #Yong Shun 's answer,
if you just want to return the list of nested documents and not all of it, you have a few options.
Using project
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
var project = Builders<Example>.Project.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId)
);
var examples = await collection.filter(filter).Project<Example>(project).toListAsync();
Using the aggregate pipeline
var filter = Builders<Example>.Filter.ElemMatch(
x => x.Family,
y => y.Countries.Any(z => z.uid == porduitId));
var project = Builders<ServiceProvider>.Projection.Expression(
x => x.Faimily.Where(y => y.uid == porduitId)
);
var result = await collection
.Aggregate()
.Match(filter)
.Project(project)
.ToListAsync(); //Here result is a list of Iterable<Countries>

How to compare single property from 2 array using c# execution time should be minimum

I have two arrays variables and values like below
arraydata1 =
[
{
"id": "1",
"name": "aaa"
},
{
"id": "2",
"name": "bbb"
},
{
"id": "3",
"name": "ccc"
},
{
"id": "4",
"name": "ddd"
},
{
"id": "12",
"name": "aaa"
}
]
and
arraydata2 =
[
{
"id": "111",
"tablename": "aaa"
},
{
"id": "222",
"tablename": "bbb"
}
]
I want to compare arraydata1.name == arraydata2.tablename and if matching then form new array from arraydata1 .
output is -
[
{
"id": "1",
"name": "aaa"
},
{
"id": "2",
"name": "bbb"
},
{
"id": "12",
"name": "aaa"
}
]
I have more than 2000+ records to compare in arraydata1 how to reduce time as well. I can use normal foreach but it will take too much time to compare.
I was doing inside logic app using 2 foreach so it is taking time. so i thought better to use c# code.
One Linq solution could look like this:
var tableNameKeys = arraydata2.Select(t => t.tablename).ToHashSet();
var resultArray = arraydata1.Where(x => tableNameKeys.Contains(x.name)).ToArray();
The advantage of this approach is that HashSet.Contains
... is an O(1) operation.
Result:

Create dynamic pivot list using joins

I want to create dynamic pivot list on list which has data in below format
"products" :
{
"name": "ABC",
"Variance": [
{
"Date": "01-01-2018",
"Value": "10"
},
{
"Date": "02-01-2018",
"Value": "11"
},
{
"Date": "03-01-2018",
"Value": "12"
},
]
},
{
"name": "XYZ",
"Variance": [
{
"Date": "01-01-2018",
"Value": "22"
},
{
"Date": "03-01-2018",
"Value": "24"
},
{
"Date": "04-01-2018",
"Value": "28"
},
],
},
{
"name": "PQR",
"Variance": [
{
"Date": "01-01-2018",
"Value": "20"
},
{
"Date": "02-01-2018",
"Value": "22"
},
{
"Date": "04-01-2018",
"Value": "24"
},
],
}
I want to create pivot list so it can return data like
"NewProducts":[{
"Date": "01-01-2018",
"ABC" : "10"
"XYZ" : "22",
"PQR" : "20"
},
{
"Date": "02-01-2018",
"ABC" : "11"
"XYZ" : "null",
"PQR" : "22"
},
{
"Date": "03-01-2018",
"ABC" : "12"
"XYZ" : "24",
"PQR" : "null"
},
{
"Date": "04-01-2018",
"ABC" : "null"
"XYZ" : "28",
"PQR" : "24"
}]
I tried some approach of having joins on inner lists, but not getting required results. I want to avoid loops as my product list will vary as per selections.
I was able to join the list using for loops, but I want to have minimal use of for loops. Any suggestions would be really helpful to me.
Thanks in Advance.
Assuming you want to use a Dictionary<string,int> to hold the dynamic value pairs, you can use LINQ by first flattening the nested structure into a new flat list with SelectMany and then grouping by Date:
var ans = products.SelectMany(p => p.Variance.Select(v => new { p.name, v.Date, v.Value }))
.GroupBy(pv => pv.Date)
.Select(pvg => new { Date = pvg.Key, Fields = pvg.ToDictionary(p => p.name, p => p.Value) });

How to search a content of a document attached in elasticsearch index

I have created the index in elasticsearch as
this.client.CreateIndex("documents", c => c.Mappings(mp => mp.Map<DocUpload>
(m => m.Properties(ps => ps.Attachment
(a => a.Name(o => o.Document)
.TitleField(t => t.Name(x => x.Title).TermVector(TermVectorOption.WithPositionsOffsets))
)))));
the attachment is base64 encoded before indexing. I am not able to search a content inside any of the document. Is base64 encoding creates any problem. Can anyone please help?
Browser response is like
{
"documents": {
"aliases": {},
"mappings": {
"indexdocument": {
"properties": {
"document": {
"type": "attachment",
"fields": {
"content": {
"type": "string"
},
"author": {
"type": "string"
},
"title": {
"type": "string",
"term_vector": "with_positions_offsets"
},
"name": {
"type": "string"
},
"date": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
},
"keywords": {
"type": "string"
},
"content_type": {
"type": "string"
},
"content_length": {
"type": "integer"
},
"language": {
"type": "string"
}
}
},
"documentType": {
"type": "string"
},
"id": {
"type": "long"
},
"lastModifiedDate": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
},
"location": {
"type": "string"
},
"title": {
"type": "string"
}
}
}
},
"settings": {
"index": {
"creation_date": "1465193502636",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "5kCRvhmsQAGyndkswLhLrg",
"version": {
"created": "2030399"
}
}
},
"warmers": {}
}
}
I found the solution by adding an analyser.
var fullNameFilters = new List<string> { "lowercase", "snowball" };
client.CreateIndex("mydocs", c => c
.Settings(st => st
.Analysis(anl => anl
.Analyzers(h => h
.Custom("full", ff => ff
.Filters(fullNameFilters)
.Tokenizer("standard"))
)
.TokenFilters(ba => ba
.Snowball("snowball", sn => sn
.Language(SnowballLanguage.English)))
))
.Mappings(mp => mp
.Map<IndexDocument>(ms => ms
.AutoMap()
.Properties(ps => ps
.Nested<Attachment>(n => n
.Name(sc => sc.File)
.AutoMap()
))
.Properties(at => at
.Attachment(a => a.Name(o => o.File)
.FileField(fl=>fl.Analyzer("full"))
.TitleField(t => t.Name(x => x.Title)
.Analyzer("full")
.TermVector(TermVectorOption.WithPositionsOffsets)
)))
))
);

Categories