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();
Related
For Instance
List<BursaryPaymentSplitting> splitAccount = new List<BursaryPaymentSplitting>();
foreach ( var lineItem in splitAccount)
{
var lineItems = new RemitaSplit {
lineItemsId = lineItem.BursaryPaymentSplittingId.ToString(),
beneficiaryName = lineItem.AccountName,
beneficiaryAccount = lineItem.AccountNumber,
bankCode = lineItem.BankCode,
beneficiaryAmount = lineItem.Amount.ToString(),
deductFeeFrom = lineItem.DeductFeeFrom.ToString()
};
}
How do i make use of the variable lineItems outside the foreach function block
Declare the variable in the scope that you need it. For example:
RemitaSplit lineItems;
foreach (var lineItem in splitAccount)
{
lineItems = new RemitaSplit { /.../ };
}
// Here you can access the lineItems variable.
// Though it *might* be NULL, your code should account for that.
Though what's strange here is that you're overwriting the same variable over and over. Why? Did you mean to have a collection of objects instead of just one object? Something like this?:
var lineItems = new List<RemitaSplit>();
foreach (var lineItem in splitAccount)
{
lineItems.Add(new RemitaSplit { /.../ });
}
// Here you can access the lineItems variable.
// And this time it won't be NULL, though it may be an empty collection.
Which could potentially be simplified to:
var lineItems = splitAccount.Select(lineItem => new RemitaSplit { /.../ });
How you simplify with LINQ in this case will depend on where/how you're populating splitAccount. I'm assuming the example in the question is just a contrived line of code to show the type of that variable, because if that's the exact code then of course that loop will never iterate over an empty list.
The point is, if splitAccount is an expression tree which will ultimately materialize data from a backing data source, you may not be able to directly call new RemitaSplit() within a .Select() until you materialize all of the records into memory, such as with a .ToList(), and there may be performance considerations to be made on that.
lineItems changes throughout the foreach.
Let's examine the code.
foreach ( var lineItem in splitAccount)
{
var lineItems = new RemitaSplit {
This translates to something like this: For each element in splitAccount create a new single reference called lineItems and assign a new RemitaSplit object to it. The type of lineItems will be RemitaSplit, it will not be List<RemitaSplit>.
Solution
I suspect you need something like the following.
using System.Linq;
(...)
var lineItems = splitAccount.Select( lineItem => new RemitaSplit { ... } ).ToList();
with foreach
var lineItems = new List<RemitaSplit>();
foreach ( var lineItem in splitAccount)
{
//item, not items
var lineItem = new RemitaSplit {
lineItemsId = lineItem.BursaryPaymentSplittingId.ToString(),
(...)
};
lineItems.Add(lineItem);
}
Edit: json
My objective is to serialize the lineItems and post as json
using Newtonsoft.Json;
using System.Linq;
(...)
var lineItems = splitAccount.Select( lineItem =>
new RemitaSplit {
lineItemsId = lineItem.BursaryPaymentSplittingId.ToString(),
(...)
}).ToList();
// Wrapping in an object, as an example,
// the web doesn't like top level json arrays
// https://stackoverflow.com/questions/3503102/what-are-top-level-json-arrays-and-why-are-they-a-security-risk
// but what you send will be guided by the api the json is sent to.
var json = JsonConvert.SerializeObject( new { Items = lineItems });
I'm trying to add one list to another . So I have this main list that I'm going to build. I loop through records and built a list and want this list to main list every time I loop. I'm trying to do this in C#.
I'm using following code. Add() function is not working.I'm getting syntax error.
IList<CgValDetail> cgValDetail = null;
//Get cgValDetails for each control
foreach (UiControlScreenMetaData tempUiControls in uiControls)
{
if (tempUiControls.CgValId == null)
{
continue;
}
IList<CgValDetail> tempCgValDetail = Retrieval<CgValDetail>.Search(new { CgValId = tempUiControls.CgValId }).ToList();
if (!tempCgValDetail.Any())
{
_foundationService.LogBusinessError(null, new ParameterBuilder("CgValId", tempUiControls.CgValId), "Invalid_CgValId_found");
return false;
}
//Add tempCgValDetail List to main list which is cgValDetail
cgValDetail.Add(tempCgValDetail);
}
Take a look at AddRange.
var firstList = new List<string>();
var secondList = new List<string>() { "a", "b" };
firstList.AddRange(secondList);
You mentioned that you don't have access to AddRange... The problem is that you're using an IList, which doesn't implement AddRange. Check this out for more on why: Why doesn't IList support AddRange
I would advise you to switch to List.
First, you need to instantiate cgValDetail as a new list, not a null.
Then you should decide if you want to declare cgValDetail as IList instead of a List. If yes, try this:
IList<CgValDetail> cgValDetail = new List<CgValDetail>();
//Get cgValDetails for each control
foreach (UiControlScreenMetaData tempUiControls in uiControls)
{
if (tempUiControls.CgValId == null)
{
continue;
}
IList<CgValDetail> tempCgValDetail = Retrieval<CgValDetail>.Search(new { CgValId = tempUiControls.CgValId }).ToList();
if (!tempCgValDetail.Any())
{
_foundationService.LogBusinessError(null, new ParameterBuilder("CgValId", tempUiControls.CgValId), "Invalid_CgValId_found");
return false;
}
//Add tempCgValDetail List to main list which is cgValDetail
((List<CgValDetail>)cgValDetail).AddRange(tempCgValDetail);
}
But I wonder why just not using a List instead of IList.
List<CgValDetail> cgValDetail = new List<CgValDetail>();
//Get cgValDetails for each control
foreach (UiControlScreenMetaData tempUiControls in uiControls)
{
if (tempUiControls.CgValId == null)
{
continue;
}
List<CgValDetail> tempCgValDetail = Retrieval<CgValDetail>.Search(new { CgValId = tempUiControls.CgValId }).ToList();
if (!tempCgValDetail.Any())
{
_foundationService.LogBusinessError(null, new ParameterBuilder("CgValId", tempUiControls.CgValId), "Invalid_CgValId_found");
return false;
}
//Add tempCgValDetail List to main list which is cgValDetail
cgValDetail.AddRange(tempCgValDetail);
}
Your cgValDetail is null. That's why when you add(...), you get syntax error.
Create a new IList<CgValDetail>
IList<CgValDetail> cgValDetail = new List<CgValDetail>();
Why didn't you use List<T> in stead of IList<T>?
You forgot to new it.
Just a simple example:
List<a> aList= new List<a>();
List<aList> List_aList = new List<aList>();
List_aList.add(new aList());
Here the link to same question.
Maybe, you can use "UNION" in Linq (if you don't really care about performance or result set is not big enough).
cgValDetail.Add(tempCgValDetail);
change to
cgValDetail = cgValDetail.Union(tempCgValDetail.Select(a => a)).ToList();
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 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()
{
// ...
};
How do I transfer the items contained in one List to another in C# without using foreach?
You could try this:
List<Int32> copy = new List<Int32>(original);
or if you're using C# 3 and .NET 3.5, with Linq, you can do this:
List<Int32> copy = original.ToList();
I see that this answer is still getting upvotes. Well, here's a secret for ya: the above answer is still using a foreach. Please don't upvote this any further.
To add the contents of one list to another list which already exists, you can use:
targetList.AddRange(sourceList);
If you're just wanting to create a new copy of the list, see the top answer.
For a list of elements
List<string> lstTest = new List<string>();
lstTest.Add("test1");
lstTest.Add("test2");
lstTest.Add("test3");
lstTest.Add("test4");
lstTest.Add("test5");
lstTest.Add("test6");
If you want to copy all the elements
List<string> lstNew = new List<string>();
lstNew.AddRange(lstTest);
If you want to copy the first 3 elements
List<string> lstNew = lstTest.GetRange(0, 3);
And this is if copying a single property to another list is needed:
targetList.AddRange(sourceList.Select(i => i.NeededProperty));
This method will create a copy of your list but your type should be serializable.
Use:
List<Student> lstStudent = db.Students.Where(s => s.DOB < DateTime.Now).ToList().CopyList();
Method:
public static List<T> CopyList<T>(this List<T> lst)
{
List<T> lstCopy = new List<T>();
foreach (var item in lst)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, item);
stream.Position = 0;
lstCopy.Add((T)formatter.Deserialize(stream));
}
}
return lstCopy;
}
Easy to map different set of list by linq without for loop
var List1= new List<Entities1>();
var List2= new List<Entities2>();
var List2 = List1.Select(p => new Entities2
{
EntityCode = p.EntityCode,
EntityId = p.EntityId,
EntityName = p.EntityName
}).ToList();
Adding to the top answers, if you want copies of "the objects in the list", then you can use Select and make the copies. (While the other answers make "a copy of a list", this answer makes "a list of copies").
Suppose your item has a Copy method:
List<MyObject> newList = oldList.Select(item => item.Copy()).ToList();
Or that you can create a new object from the previous one with a constructor:
List<MyObject> newList = oldList.Select(item => new MyObject(item)).ToList();
The result of Select is an IEnumerable<MyObject> that you can also pass to AddRange for instance, if your goal is to add to an existing list.
OK this is working well
From the suggestions above GetRange( ) does not work for me with a list as an argument...so sweetening things up a bit from posts above: ( thanks everyone :)
/* Where __strBuf is a string list used as a dumping ground for data */
public List < string > pullStrLst( )
{
List < string > lst;
lst = __strBuf.GetRange( 0, __strBuf.Count );
__strBuf.Clear( );
return( lst );
}
public static List<string> GetClone(this List<string> source)
{
return source.Select(item => (string)item.Clone()).ToList();
}
Here another method but it is little worse compare to other.
List<int> i=original.Take(original.count).ToList();