I have collection of objects which has property with type of collection.
How can i quick migrate objects property to the one of collection object with help Linq.
Class obj
{
list<int> aa;
List<obj> b = new List<obj>()
{
new obj()
{
aa = new List<int>(){1,2,3}
},
new obj()
{
aa = new List<int>(){4,5,6}
}
}
}
i need to migrate all properties name "aa" of objects collection to one collection.
Thanks.
Use LINQ and SelectMany:
var result = b.SelectMany(o=>o.aa).ToList();
Related
This question already has answers here:
How to flatten nested objects with linq expression
(4 answers)
Linq nested list expression
(2 answers)
Closed 7 years ago.
I have a list of a custom car object List<Car>. The car class has two properties 'BrandName' and 'Models' as defined below.
public class Car
{
public string BrandName {get; set;}
public List<string> Models {get; set;}
}
The data for the 'List` object is populated from an API as below. It returns close to 200 rows. For illustration purposes, the object has been instantiated with two items as below. The object is returned from the API with this structure and I have no control over how the data is structured and sent.
List<Car> listCarObj = new List<Car>(){
new Car(){ BrandName = "Mercedes", Models = new List<string>(){"Class A", "Class E"}},
new Car(){ BrandName = "BMW", Models = new List<string>(){"X Series", "E Series"}}
}
How do I convert this list to an IEnumerable or another List of an anonymous type having data in the below format using Linq?
var obj = new[] {new {brand = "Mercedes", model = "Class A"},
new {brand = "Mercedes", model = "Class E"},
new {brand = "BMW", model = "X Series"},
new {brand = "BMW", model = "E Series"}};
Thanks in advance..
here is a approach with SelectMany and a nested Select
var result = listCarObj.SelectMany(x => x.Models.Select(y => new { model = y,brand = x.BrandName }));
Why don't you make a linq query, in which you select every object from the listCarObj and, for every element from the list, get all the models and return an anonymous type?
Something like:
var obj = from p in listCarObj
from q in p.Models
select new {
brand=p.BrandName,
model = q
};
You can use SelectMany to flatten your Models and then project it like this:-
var result = listCarObj.SelectMany(x => x.Models,
(carObj, model) => new {
carObj.BrandName, model
});
I need your help
I just wrote the following code
var anynomousObject = new { Amount = 10, weight = 20 };
List<object> ListOfAnynomous = new List<object> { anynomousObject };
var productQuery =
from prod in ListOfAnynomous
select new { prod.Amount, prod.weight }; // here it object on 'prod.Amount, prod.weight' that the object defenetion does not contains the "Amount" and "weight" properties
foreach (var v in productQuery)
{
Console.WriteLine(v.Amount, v.weight);
}
so please could you help me to solve this problem.
You need to make a class of your object definition, or using the dynamic keywork instead of boxing in object :
var anynomousObject = new { Amount = 10, weight = 20 };
List<dynamic> ListOfAnynomous = new List<dynamic> { anynomousObject };
var productQuery =
from prod in ListOfAnynomous
select new { prod.Amount, prod.weight };
foreach (var v in productQuery)
{
Console.WriteLine(v.Amount, v.weight);
}
this is because, when you box as object, the compiler doesn't know the definition of your anonymous var. Dynamic make it evaluate at runtime instead of compile-time.
The other option is to create a class or struct.
Your List<object> has a list of objects. The Linq query looks this list, and all it sees are regular objects.
Either use a class or a structure to store your objects, or use List<dynamic>
I have a class named DataAPIKey. I have a second class which inherits from that one.
In my code I have a List, and I would like to use that to make a list of the new class. Is there any way to do this without using a for each loop?
Using the example below I made the following code which seems to be doing what I want.
List<DataAPIKey> apiList = db.GetPendingAction("Character");
List<DataCharacter> charList = apiList.Select(k => {
DataCharacter dc = new DataCharacter(k.apiKeyId, k.keyId, k.verificationCode);
return dc;
}).ToList()
Use the LINQ Select method.
var newList = oldList.Select(oldItem => new InheritedItem(oldItem)).ToList();
In plain English this translates to "Take each item from oldList, feed each as a function parameter to a function which will take that item and perform some logic to return a different type of item, then take all the returned items and populate them into a new List."
Or if you don't have a constructor to initialize the inherited class then you can provide any code block:
var newList = oldList.Select(oldItem =>
{
var newItem = new InheritedItem();
newItem.Property = oldItem.Property;
return newItem;
}).ToList();
Or an initializer:
var newList = oldList.Select(oldItem => new InheritedItem()
{
Property = oldItem.Property,
Property2 = oldItem.Property2
}).ToList();
I think I understand returning records of an anonymous type from But in this I want to create NEW CatalogEntries, and set them from the values selected. (context is a Devart LinqConnect database context, which lets me grab a view).
My solution works, but it seems clumsy. I want to do this in one from statement.
var query = from it in context.Viewbostons
select it;
foreach (GPLContext.Viewboston item in query)
{
CatalogEntry card = new CatalogEntry();
card.idx = item.Idx;
card.product = item.Product;
card.size = (long)item.SizeBytes;
card.date = item.Date.ToString();
card.type = item.Type;
card.classification = item.Classification;
card.distributor = item.Distributor;
card.egplDate = item.EgplDate.ToString();
card.classificationVal = (int)item.ClassificationInt;
card.handling = item.Handling;
card.creator = item.Creator;
card.datum = item.Datum;
card.elevation = (int)item.ElevationFt;
card.description = item.Description;
card.dirLocation = item.DoLocation;
card.bbox = item.Bbox;
card.uniqID = item.UniqId;
values.Add(card);
}
CatalogResults response = new CatalogResults();
I just tried this:
var query2 = from item in context.Viewbostons
select new CatalogResults
{ item.Idx,
item.Product,
(long)item.SizeBytes,
item.Date.ToString(),
item.Type,
item.Classification,
item.Distributor,
item.EgplDate.ToString(),
(int)item.ClassificationInt,
item.Handling,
item.Creator,
item.Datum,
(int)item.ElevationFt,
item.Description,
item.DoLocation,
item.Bbox,
item.UniqId
};
But I get the following error:
Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a
collection initializer because it does not implement
'System.Collections.IEnumerable' C:\Users\ysg4206\Documents\Visual
Studio
2010\Projects\CatalogService\CatalogService\CatalogService.svc.cs 91 25 CatalogService
I should tell you what the definition of the CatalogResults is that I want to return:
[DataContract]
public class CatalogResults
{
CatalogEntry[] _results;
[DataMember]
public CatalogEntry[] results
{
get { return _results; }
set { _results = value; }
}
}
My mind is dull today, apologies to all. You are being helpful. The end result is going to be serialized by WCF to a JSON structure, I need the array wrapped in a object with some information about size, etc.
Since .NET 3.0 you can use object initializer like shown below:
var catalogResults = new CatalogResults
{
results = context.Viewbostons
.Select(it => new CatalogEntry
{
idx = it.Idx,
product = it.Product,
...
})
.ToArray()
};
So if this is only one place where you are using CatalogEntry property setters - make all properties read-only so CatalogEntry will be immutable.
MSDN, Object initializer:
Object initializers let you assign values to any accessible fields or properties of an
object at creation time without having to explicitly invoke a constructor.
The trick here is to create a IQueryable, and then take the FirstOrDefault() value as your response (if you want a single response) or ToArray() (if you want an array). The error you are getting (Error 79 Cannot initialize type 'CatalogService.CatalogResults' with a collection initializer because it does not implement 'System.Collections.IEnumerable') is because you're trying to create an IEnumerable within the CatalogEntry object (by referencing the item variable).
var response = (from item in context.Viewbostons
select new CatalogEntry()
{
idx = item.Idx,
product = item.Product,
size = (long)item.SizeBytes,
...
}).ToArray();
You don't have to create anonymous types in a Linq select. You can specify your real type.
var query = context.Viewbostons.Select( it =>
new CatalogEntry
{
idx = it.idx,
... etc
});
This should work:
var query = from it in context.Viewbostons
select new CatalogEntry()
{
// ...
};
Can I retrieve basic information about all collections in a MongoDB with F#?
I have a MongoDB with > 450 collections. I can access the db with
open MongoDB.Bson
open MongoDB.Driver
open MongoDB.Driver.Core
open MongoDB.FSharp
open System.Collections.Generic
let connectionString = "mystring"
let client = new MongoClient(connectionString)
let db = client.GetDatabase(name = "Production")
I had considered trying to just get all collections then loop through each collection name and get basic information about each collection with
let collections = db.ListCollections()
and
db.GetCollection([name of a collection])
but the db.GetCollection([name]) requires me to define a type to pull the information about each collection. This is challenging for me as I don't want to have to define a type for each collection, of which there are > 450, and frankly, I don't really know much about this DB. (Actually, no one in my org does; that's why I'm trying to put together a very basic data dictionary.)
Is defining the type for each collection really necessary? Can I use the MongoCollection methods available here without having to define a type for each collection?
EDIT: Ultimately, I'd like to be able to output collection name, the n documents in each collection, a list of the field names in each collection, and a list of each field type.
I chose to write my examples in C# as i'm more familiar with the C# driver and it is a listed tag on the question. You can run an aggregation against each collection to find all top level fields and their (mongodb) types for each document.
The aggregation is done in 3 steps. Lets assume the input is 10 documents which all have this form:
{
"_id": ObjectId("myId"),
"num": 1,
"str": "Hello, world!"
}
$project Convert each document into an array of documents with values fieldName and fieldType. Outputs 10 documents with a single array field. The array field will have 3 elements.
$unwind the arrays of field infos. Outputs 30 documents each with a single field corresponding to an element from the output of step 1.
$group the fields by fieldName and fieldType to get distinct values. Outputs 3 documents. Since all fields with the same name always have the same type in this example, there is only one final output document for each field. If two different documents defined the same field, one as string and one as int there would be separate entries in this result set for both.
// Define our aggregation steps.
// Step 1, $project:
var project = new BsonDocument
{ {
"$project", new BsonDocument
{
{
"_id", 0
},
{
"fields", new BsonDocument
{ {
"$map", new BsonDocument
{
{ "input", new BsonDocument { { "$objectToArray", "$$ROOT" } } },
{ "in", new BsonDocument {
{ "fieldName", "$$this.k" },
{ "fieldType", new BsonDocument { { "$type", "$$this.v" } } }
} }
}
} }
}
}
} };
// Step 2, $unwind
var unwind = new BsonDocument
{ {
"$unwind", "$fields"
} };
// Step 3, $group
var group = new BsonDocument
{
{
"$group", new BsonDocument
{
{
"_id", new BsonDocument
{
{ "fieldName", "$fields.fieldName" },
{ "fieldType", "$fields.fieldType" }
}
}
}
}
};
// Connect to our database
var client = new MongoClient("myConnectionString");
var db = client.GetDatabase("myDatabase");
var collections = db.ListCollections().ToEnumerable();
/*
We will store the results in a dictionary of collections.
Since the same field can have multiple types associated with it the inner value corresponding to each field is `List<string>`.
The outer dictionary keys are collection names. The inner dictionary keys are field names.
The inner dictionary values are the types for the provided inner dictionary's key (field name).
List<string> fieldTypes = allCollectionFieldTypes[collectionName][fieldName]
*/
Dictionary<string, Dictionary<string, List<string>>> allCollectionFieldTypes = new Dictionary<string, Dictionary<string, List<string>>>();
foreach (var collInfo in collections)
{
var collName = collInfo["name"].AsString;
var coll = db.GetCollection<BsonDocument>(collName);
Console.WriteLine("Finding field information for " + collName);
var pipeline = PipelineDefinition<BsonDocument, BsonDocument>.Create(project, unwind, group);
var cursor = coll.Aggregate(pipeline);
var lst = cursor.ToList();
allCollectionFieldTypes.Add(collName, new Dictionary<string, List<string>>());
foreach (var item in lst)
{
var innerDict = allCollectionFieldTypes[collName];
var fieldName = item["_id"]["fieldName"].AsString;
var fieldType = item["_id"]["fieldType"].AsString;
if (!innerDict.ContainsKey(fieldName))
{
innerDict.Add(fieldName, new List<string>());
}
innerDict[fieldName].Add(fieldType);
}
}
Now you can iterate over your result set:
foreach(var collKvp in allCollectionFieldTypes)
{
foreach(var fieldKvp in collKvp.Value)
{
foreach(var fieldType in fieldKvp.Value)
{
Console.WriteLine($"Collection {collKvp.Key} has field name {fieldKvp.Key} with type {fieldType}");
}
}
}