take out foreach using linq - c#

Is there a way to take out the foreach in the following code in linq yet produce the same output?
DropDownList ddl = new DropDownList();
foreach (DataRow row in ds.Tables[0].Rows)
{
if ((byte)row["ListTypeID"] == 0)
{
item = new ListItem(row["ListText"].ToString(), string.Format("{0}:{1}", row["ListTypeID"].ToString(), row["ListID"].ToString()));
ddl.Items.Add(item);
}
else
{
item = new ListItem(row["ListText"].ToString(), string.Format("{0}", row["ListID"].ToString()));
ddl.Items.Add(item);
}
}

Instead of cramming all into a one-line lambda, I prefer readability over saving line space:
ddl.Items.AddRange(ds.Tables[0].Rows.Select( row =>
{
var listText = row["ListText"];
var listTypeId = (byte)row["ListTypeID"];
var listId = row["ListID"];
var format = listTypeId == 0 ? "{0}:{1}" : "{1}";
var itemText = String.Format(format, listTypeID, listId);
return new ListItem(listText, itemText);
}
));

ddl.Items.AddRange(ds.Tables[0].Rows.Select( row =>
(byte)row["ListTypeID"] == 0
? new ListItem(row["ListText"].ToString(), string.Format("{0}:{1}", row["ListTypeID"].ToString(), row["ListID"].ToString()))
: new ListItem(row["ListText"].ToString(), string.Format("{0}", row["ListID"].ToString()))
));
a bit of cleaning
ddl.Items.AddRange(ds.Tables[0].Rows.Select( row =>
(byte)row["ListTypeID"] == 0
? new ListItem(row["ListText"].ToString(), string.Format("{0}:{1}", row["ListTypeID"], row["ListID"]))
: new ListItem(row["ListText"].ToString(), string.Format("{0}", row["ListID"]))
));
leave foreach :)

After a bit of reordering you can achieve the following - adding the items excluded.
var items = ds.Tables[0].Rows.Select(row =>
new ListItem(row["ListText"].ToString(),
String.Format(
(Byte)row["ListTypeID"] == 0 ? "{0}:{1}" : "{1}",
row["ListTypeID"], row["ListID"])));

You can use something like this
var Items= (from DataRow dr in ds.Tables[0].AsEnumerable()
select new {
Text=dr.Field<string>("ListText"),
Value =dr.Field<byte>("ListTypeID") == 0?string.Format("{0}:{1}", dr.Field<string>("ListTypeID"), dr.Field<string>("ListID")):string.Format("{0}", dr.Field<string>("ListID"))
}).ToList();
now you can use Items as data-source for the dropdown.

Related

How can I compare a value from List<string> to Project.Models.Class?

I want to retrieve data from Project.Models.transaction_details by using linq, comparing value from list of string (List).
here is my code
List<transaction_details> transactions = new List<transaction_details>();
List<string> date_list = new List<string>();
// date_list output is ["2020-01-01","2020-01-02",2020-01-03",...,"2020-01-31"]
while (sdr.Read())
{
transactions.Add(new transaction_details
{
ID = sdr.GetInt32("ID"),
Transdate = sdr.GetDateTime("Transdate"),
Debit = sdr.GetDecimal("Debit"),
TransactionName =sdr.GetString("TransactionName"),
BranchID = sdr.GetString("BranchID")
});
}
var array1Index = date_list.Select((i, index) => new { Index = index, i = i }).ToList();
List<transaction_details> arrayresult = new List<transaction_details>();
var query1 = from a in array1Index
select transactions.Contains(a.i) == true ? a.i : "";
arrayresult = query1.ToList();
arrayresult.ForEach(x => {
Console.Write(x + " ");
});
My problem is (a.i) is an error.
Cannot convert 'string' to 'Project.Models.transaction_details'.
you probably mean to check the transaction date. try this:
var query1 = from a in array1Index
select transactions.Any(t => t.Transdate == a.i) == true ? a.i : "";
EDIT:
if you want a list of transactions try this:
var query1 = from t in transactions
where array1Index.Any(a => a.i == t.Transdate)
select t;
var query1 = from t in transactions
where array1Index.Any(a => a.i == t.Transdate);
try this

c# linq create dynamic query with

I have 5 Dropdown lists which are filled with the columns of my dataset.
That works well.
var query = ds.Tables["Input"].AsEnumerable().Select
(a => new
{ID = a.Field<string>("ID"),
Element1 = a.Field<string>(comboBoxElement1.SelectedItem.ToString()),
Element2 = a.Field<string>(comboBoxElement2.SelectedItem.ToString()),
Element3 = a.Field<string>(comboBoxElement3.SelectedItem.ToString()),
Element4 = a.Field<string>(comboBoxElement4.SelectedItem.ToString()),
Element5 = a.Field<string>(comboBoxElement5.SelectedItem.ToString())});
But that only works if all ComboBoxes are not empty.
How can I build the query with only 2 selected Boxes dynamically?
I tried it with a StingBuilder and if (comboBoxName.SelectedIndex >= 0) statements, but I'm wondering if there is another method to do that within LINQ.
Why not add a where clause asking for only selectedIndex != 0
like this (in a WinForm):
result = Controls.OfType<ComboBox>().Where(cb => cb.SelectedIndex != -1).Aggregate(result, (current, cb) => current + (cb.SelectedItem + ","));
Have you try this:
var query = ds.Tables["Input"].AsEnumerable().Where(cb => cb.SelectedIndex != -1).Select
(a => new
{ID = a.Field<string>("ID"),
Element1 = a.Field<string>(comboBoxElement1.SelectedItem.ToString()),
Element2 = a.Field<string>(comboBoxElement2.SelectedItem.ToString()),
Element3 = a.Field<string>(comboBoxElement3.SelectedItem.ToString()),
Element4 = a.Field<string>(comboBoxElement4.SelectedItem.ToString()),
Element5 = a.Field<string>(comboBoxElement5.SelectedItem.ToString())});
I found a easy solution.
Create a List from the (not empty) ComboBoxes:
List<string> myCollection = new List<string>();
if (comboBoxElement1.SelectedIndex >= 0)
{
myCollection.Add(comboBoxElement1.SelectedItem.ToString());
}
if (comboBoxElement2.SelectedIndex >= 0)
{
myCollection.Add(comboBoxElement2.SelectedItem.ToString());
}
Create a DataView from the InputTable:
DataView dv = new DataView(dtInput);
Write to the selected DataColumns from comboBoxes to the ouputTable:
dtOutput = dv.ToTable(true, myCollection.ToArray());
You can refactor the above by creating a method such as:
public AddSelected(IList list, params ComboBox[] comboBoxes)
{
foreach (var comboBox in comboBoxes)
{
if (comboBox.SelectedIndex >= 0)
{
list.Add(comboBox.SelectedItem.ToString());
}
}
}
Then calling with code such as:
AddSelected(myCollection, comboBoxElement1, comboBoxElement2 /* , ... */ );

Optimization of nested loops using LINQ

Can you please suggest how to write an optmized LINQ query for the following operation?
foreach (DataRow entry1 in table1.Rows)
{
var columnA = entry1["ColumnA"] as string;
if (!string.IsNullOrEmpty(columnA))
{
foreach (string entry2 in table2)
{
var dataExists = table3.Any(rows3 =>
!string.IsNullOrEmpty(rows3[entry2] as string)
&& columnA.IsEqual(rows3["ColumnB"] as string));
if (dataExists)
{
entry1[entry2] = Compute(columnA, entry2);
}
}
}
}
I tried with this, but the results don't match in terms of the unique iteration counts.
var t2t3Pair = from entry2 in table2
let entry3 = table3.FirstOrDefault(x =>
!string.IsNullOrEmpty(x[entry2] as string))
where entry3 != null
select new { entry2, entry3 };
var t1t3Pair = from pair in t2t3Pair
from entry1 in table1.AsEnumerable()
let columnA = entry1["ColumnA"] as string
where !string.IsNullOrEmpty(columnA)
&& columnA.IsEqual(pair.entry3["ColumnB"] as string)
select new { Entry1Alias = entry1, Entry2Alias = pair.entry2 };
foreach (var pair in t1t3Pair)
{
var columnA = (string)pair.Entry1Alias["ColumnA"];
pair.Entry1Alias[pair.Entry2Alias] = Compute(columnA, pair.Entry2Alias);
}
Note: IsEqual is my extension method to compare string without case sensitivity.
Apparently the bottleneck is the line
var dataExists = table3.Any(rows3 =>
!string.IsNullOrEmpty(rows3[entry2] as string)
&& columnA.IsEqual(rows3["ColumnB"] as string));
which is executed inside the innermost loop.
As usual, it can be optimized by preparing in advance a fast lookup data structure and use it inside the critical loop.
For your case, I would suggest something like this:
var dataExistsMap = table3.AsEnumerable()
.GroupBy(r => r["ColumnB"] as string)
.Where(g => !string.IsNullOrEmpty(g.Key))
.ToDictionary(g => g.Key, g => new HashSet<string>(
table2.Where(e => g.Any(r => !string.IsNullOrEmpty(r[e] as string)))
// Include the proper comparer if your IsEqual method is using non default string comparison
//, StringComparer.OrdinalIgnoreCase
)
);
foreach (DataRow entry1 in table1.Rows)
{
var columnA = entry1["ColumnA"] as string;
if (string.IsNullOrEmpty(columnA)) continue;
HashSet<string> dataExistsSet;
if (!dataExistsMap.TryGetValue(columnA, out dataExistsSet)) continue;
foreach (string entry2 in table2.Where(dataExistsSet.Contains))
entry1[entry2] = Compute(columnA, entry2);
}

Replace foreach to make loop into queryable

I have a function returning a report object, but currently i am going through a foreach look and then using the asQueryable method.
I would like to do it in one query and not have to use the AsQueryable function.
var query = from item in context.Dealers
where item.ManufacturerId == manufacturerId
select item;
IList<DealerReport> list = new List<DealerReport>();
foreach (var deal in query)
{
foreach (var bodyshop in deal.Bodyshops1.Where(x => x.Manufacturer2Bodyshop.Select(s => s.ManufacturerId).Contains(manufacturerId)))
{
DealerReport report = new DealerReport();
report.Dealer = deal.Name;
report.Bodyshop = bodyshop.Name;
short stat = bodyshop.Manufacturer2Bodyshop.FirstOrDefault(x => x.ManufacturerId == manufacturerId).ComplianceStatus;
report.StatusShort = stat;
list.Add(report);
}
}
return list.OrderBy(x => x.Dealer).AsQueryable();
I think you want something like this:
var query = from deal in context.Dealers
where deal.ManufacturerId == manufacturerId
from bodyshop in deal.Bodyshops1
where bodyshop.Manufacturer2Bodyshop.Select(s => s.ManufacturerId).Contains(manufacturerId)
let stat = bodyshop.Manufacturer2Bodyshop.FirstOrDefault(x => x.ManufacturerId == manufacturerId)
orderby deal.Name
select new DealerReport
{
Dealer = deal.Name,
Bodyshop = bodyshop.Name,
StatusShort = stat != null ? stat.ComplianceStatus : 0, // or some other default
};
return query;

how convert DataTable to List<String> in C#

I am using C# Linq now I am converting DataTable to List
and I am getting stuck...
give me right direction thanks..
private void treeview1_Expanded(object sender, RoutedEventArgs e)
{
coa = new List<string>();
//coa = (List<string>)Application.Current.Properties["CoAFull"];
HMDAC.Hmclientdb db = new HMDAC.Hmclientdb(HMBL.Helper.GetDBPath());
var data = (from a in db.CoA
where a.ParentId == 0 && a.Asset == true
select new { a.Asset, a.Category, a.CoAName, a.Hide, a.Recurring, a.TaxApplicable });
DataTable dtTable = new DataTable();
dtTable.Columns.Add("Asset", typeof(bool));
dtTable.Columns.Add("Category", typeof(string));
dtTable.Columns.Add("CoAName", typeof(string));
dtTable.Columns.Add("Hide", typeof(bool));
dtTable.Columns.Add("Recurring", typeof(bool));
dtTable.Columns.Add("TaxApplicable", typeof(bool));
if (data.Count() > 0)
{
foreach (var item in data)
{
DataRow dr = dtTable.NewRow();
dr["Asset"] = item.Asset;
dr["Category"] = item.Category;
dr["CoAName"] = item.CoAName;
dr["Hide"] = item.Hide;
dr["Recurring"] = item.Recurring;
dr["TaxApplicable"] = item.TaxApplicable;
dtTable.Rows.Add(dr);
}
}
coa = dtTable;
}
It seems that you already have a strongly typed list. Why converting this to a weakly typed DataTable and then back to a list?????
var data =
from a in db.CoA
where a.ParentId == 0 && a.Asset == true
select new
{
a.Asset,
a.Category,
a.CoAName,
a.Hide,
a.Recurring,
a.TaxApplicable
};
var list = data.ToList();
If you want to be able to use this list outside the scope of the method, define a type that will hold the different properties and in your select statement use this type instead of the anonymous type like:
var data =
from a in db.CoA
where a.ParentId == 0 && a.Asset == true
select new MyType
{
Asset = a.Asset,
Category = a.Category,
CoAName = a.CoAName,
Hide = a.Hide,
Recurring = a.Recurring,
TaxApplicable = a.TaxApplicable
};
List<MyType> list = data.ToList();
You don't need the data table according to the code you have displayed:
var data = (from a in db.CoA
where a.ParentId == 0 && a.Asset == true
select new { a.Asset.ToString() + a.Category.ToString()
+ a.CoAName.ToString()... }).ToList();
If you really want to convert your datatable to a 1D list, you can do it like this
foreach (DataRow row in dtTable.Rows)
{
foreach (DataColumn col in dtTable.Columns)
{
coa.Add(row[col]);
}
}
As you are using Select new in you linq query It will find object. What you can do is
var data = (from a in db.CoA
where a.ParentId == 0 && a.Asset == true
select new { a.Asset, a.Category, a.CoAName, a.Hide, a.Recurring, a.TaxApplicable });
this is your query and you select multiple columns in your query. So you can't convert your data to a single List of string. What you can do is concatenate all the column in a single string and then add them in a list of string.
To do that modify your query like 'CK' said
var data = (from a in db.CoA
where a.ParentId == 0 && a.Asset == true
select new { a.Asset.ToString() + a.Category.ToString()
+ a.CoAName.ToString()... }).ToList();
And then do
List<string> name = new List<string>(data.ToList());

Categories

Resources