Assign Values to object properties by Id - c#

I have a global list of objects used to hold values, values along with the Ids will be parsed into the ObjectManager function, the Ids can only ever be what is stated in the list. I want the function to update the value that corresponds to the Id.
Initially I tried to use a foreach loop which wasn't updating the objects in the list. Using the below code does update the objects in the list, but it only checks for the id that's parsed in, I am now trying this with a switch statement, early days.
What is the best way of achieving what I'm trying to do?
Sample Code:
public List<Object> obj = new List<Object>
{
new Object { id = 4, val = 20 },
new Object { id = 1, val = 34 },
new Object { id = 16, val = 27 },
new Object { id = 9, val = 36 }
};
public void ObjectManager(List<Object> myobj, int id, int val)
{
int i = 0;
int j = 0;
while (i < myobj.Count)
{
if(myobj[i].id == id)
{
j = myobj[i].val;
myobj[i].val = j + val;
}
}
}

You can select the item that you want to update using FirstOrDefault()
var variable = myobj.FirstOrDefault(o=>o.id = "YOUR_ID"
FirstOrDefault() returns null if the item is not found, so we need to check for null before updating the item
if (variable != null) variable.val = YOUR_VALUE

You should use Dictionary for this.
You'll find many solutions related add or update in Dictionary. like this or this

Related

How to get all the values from an SQL Query C#

I have used String Builder to generate a RAW SQL QUERY in C#.
List<string> columns = new List<string>();
columns.Add("id");
columns.Add("Temp");
StringBuilder SqlStatement = new StringBuilder();
SqlStatement.Append("Select ");
for (int i = 0; i < columns.Count; i++)
{
if (i == columns.Count - 1)
{
SqlStatement.Append(columns[i]);
}
else
{
SqlStatement.Append(columns[i]);
SqlStatement.Append(",");
}
}
SqlStatement.Append(" FROM graph_update");
var ctx = new graphDBContext();
var result = ctx.Database.SqlQuery<graphDBContext>(SqlStatement.ToString()).ToList();
This translates into SELECT id,Temp FROM graph_update
And the result gives me
id = 1, temp = 20
id = 2 temp = 30
How do I get all these values????
I'm too use to:
foreach(var item in result)
{
item.id = id;
item.temp = temp;
}
But it won't let me.
EDIT:
Sorry but I'm not sure what you mean. Here is my debugger
Try to use foreach like this if theres no error return
foreach(var v in result)
{
String v0 = v[0].ToString();
String v1 = v[1].ToString();
}
Assuming you have EF > 6, then the ctx.Database.SqlQuery, according to the method documentation:
Creates a raw SQL query that will return elements of the given generic type.
The type can be any type that has properties that match the names of the columns returned from the query, or can be a simple primitive type. The type does not have to be an entity type. The results of this query are never tracked by the context even if the type of object returned is an entity type.
With that in mind you can do something like this:
public class GraphUpdateResult
{
public int Id {get; set;}
public decimal Temp {get; set;}
}
Then in your current method:
var result = ctx.Database.SqlQuery<GraphUpdateResult>SqlStatement.ToString()).ToList();
foreach (var graphResult in result)
{
Console.WriteLine(graphResult.Id);
Console.WriteLine(graphResult.Temp);
}
You can add more columns to the GraphUpdateResult class for EF to bind to, even if in some queries you don't specify them in the select statement.
I hope this helps.
foreach(var item in result)
{
var id = item.id;
var temp = item.temp;
}
in your code above, you are trying to assign the values to the item, instead of retrieving.
You can use a ORM-Mapper like
https://stormy.codeplex.com/SourceControl/latest#Stormy.cs
It is a very light Mapper and you can look how it works.
It maps the reader Data to the Object data:
public class CatMapper : ISelectable<Cat>
{
public Cat ApplySelect(IDataReader reader)
{
return new Cat()
{
Name = reader["name"].ToString(),
Weight = (float)reader["weight"]
};
}
}

How to dynamically GroupBy using Linq

There are several similar sounding posts, but none that do exactly what I want.
Okay, so imagine that I have the following data structure (simplified for this LinqPad example)
public class Row
{
public List<string> Columns { get; set; }
}
public List<Row> Data
=> new List<Row>
{
new Row { Columns = new List<string>{ "A","C","Field3"}},
new Row { Columns = new List<string>{ "A","D","Field3"}},
new Row { Columns = new List<string>{ "A","C","Field3"}},
new Row { Columns = new List<string>{ "B","D","Field3"}},
new Row { Columns = new List<string>{ "B","C","Field3"}},
new Row { Columns = new List<string>{ "B","D","Field3"}},
};
For the property "Data", the user will tell me which column ordinals to GroupBy; they may say "don't group by anything", or they may say "group by Column[1]" or "group by Column[0] and Column[1]".
If I want to group by a single column, I can use:
var groups = Data.GroupBy(d => d.Columns[i]);
And if I want to group by 2 columns, I can use:
var groups = Data.GroupBy(d => new { A = d.Columns[i1], B = d.Columns[i2] });
However, the number of columns is variable (zero -> many); Data could contain hundreds of columns and the user may want to GroupBy dozens of columns.
So the question is, how can I create this GroupBy at runtime (dynamically)?
Thanks
Griff
With that Row data structure what are you asking for is relatively easy.
Start by implementing a custom IEqualityComparer<IEnumerable<string>>:
public class ColumnEqualityComparer : EqualityComparer<IEnumerable<string>>
{
public static readonly ColumnEqualityComparer Instance = new ColumnEqualityComparer();
private ColumnEqualityComparer() { }
public override int GetHashCode(IEnumerable<string> obj)
{
if (obj == null) return 0;
// You can implement better hash function
int hashCode = 0;
foreach (var item in obj)
hashCode ^= item != null ? item.GetHashCode() : 0;
return hashCode;
}
public override bool Equals(IEnumerable<string> x, IEnumerable<string> y)
{
if (x == y) return true;
if (x == null || y == null) return false;
return x.SequenceEqual(y);
}
}
Now you can have a method like this:
public IEnumerable<IGrouping<IEnumerable<string>, Row>> GroupData(IEnumerable<int> columnIndexes = null)
{
if (columnIndexes == null) columnIndexes = Enumerable.Empty<int>();
return Data.GroupBy(r => columnIndexes.Select(c => r.Columns[c]), ColumnEqualityComparer.Instance);
}
Note the grouping Key type is IEnumerable<string> and contains the selected row values specified by the columnIndexes parameter, that's why we needed a custom equality comparer (otherwise they will be compared by reference, which doesn't produce the required behavior).
For instance, to group by columns 0 and 2 you could use something like this:
var result = GroupData(new [] { 0, 2 });
Passing null or empty columnIndexes will effectively produce single group, i.e. no grouping.
you can use a Recursive function for create dynamic lambdaExpression. but you must define columns HardCode in the function.

How can I compare an index value of a list item with all index of same list

i have a list which is iterating multiple times. it is having rangename as item. My requirement is perform an action when rangename at any index of this list is equal to rangename at some other index. i am using the following code.
var bList = new List<Budget.budget_data>();
for (int z = 0; z < bList.Count; z++)
{
if (bList [z].Range == bList.Where(a => bList.Any(x => x.Range ==x.Range)))
{
//need to perform action
}
}
which is giving error. How to compare one index value of a list's item with all index on same list .
From what I understand from your question, you want to perform some action when two Ranges are equal in your list. Following should work for you.
var bList = new List<Budget.budget_data>();
for (var i = 0; i < bList.Count; i++)
{
for (var j = i + 1; j < bList.Count; j++)
{
if (bList[i].Range == bList[j].Range)
{
//Perform your action
}
}
}
This will perform your action if there is any duplicate Range in the list.
Sounds like you are trying to find duplicates however without clearly knowing what you are trying to achieve its difficult to help you find an adequate solution to your problem.
Using some of the details you've provided, below is a generic solution for looping through duplicates.
public static void Main()
{
var budgets = new List<Budget>()
{
new Budget(){ Id = 1, Range = "A" },
new Budget(){ Id = 2, Range = "B" },
new Budget(){ Id = 3, Range = "C" },
new Budget(){ Id = 4, Range = "C" },
new Budget(){ Id = 5, Range = "A" }
};
var duplicateBudgetGroups = budgets.GroupBy(budget => budget.Range).Where(group => group.Count() > 1);
foreach (var duplicateBudgets in duplicateBudgetGroups)
{
Console.WriteLine("Duplicate Range {0}", duplicateBudgets.Key);
foreach (var budget in duplicateBudgets)
{
Console.WriteLine("Budget {{ Id = {0}, Range = {1} }}", budget.Id.ToString(), budget.Range);
}
}
}
class Budget {
public int Id { get; set; }
public string Range { get; set; }
}
I've added this to dotnetfiddle so you can see it working: https://dotnetfiddle.net/65gF6f
Not too clearly asked, I feel, but you could try this:
var bList = new List<Budget.budget_data>();
// ...
var z = ...;
for (var x = 0; x < bList.Count; ++x)
{
if (x == z)
continue;
if (bList[z].Range == bList[x].Range)
{
//need to perform action
}
}
This performs the action one time for each index x for which there is a match, so the action can run many times. If you just want one execution of the action, you may finish the if block with a break; statements (exits the loop completely).
Note: This assumes that the type of .Range is such that it is reasonable to use ==. What is the declared type of .Range?
I may have misunderstood the question. If you want to determine whether there are any duplicates at all, you can:
var bList = new List<Budget.budget_data>();
// ...
var uniqueRangeValues = new HashSet<string>();
foreach (var b in bList)
{
if (!uniqueRangeValues.Add(b.Ranges))
{
// perform action
break; // omit if you want to perform the action several times
}
}

InvalidOperationException: Sequence contains more than one element - SingleOrDefault()

using (var db = new ABC())
{
for (int column = rangeClass2.Start.Column; column <= rangeClass2.End.Column; column++)
{
var classValue = censusSheet.Cells[row, column].Value;
var description = censusSheet.Cells[3, 27].Value;
lifeReductionByData.Add(classASheet.getClassFromExcelPivotedValuedreductionBy<tbl_Life_Reduction_By>(25, 1, 33, 4, lifeReductionByClassMapper).FirstOrDefault());
for (int i = 0; i < lifeReductionByData.Count; i++)
{
lifeReductionByData[i].Class = classesValue[x];
lifeReductionByData[i].UUID = censusSheet.GetValue(25, 27).ToString();
}
}
var entry = new tbl_Life_Master() { UUID = uuidVar };
entry.tbl_Life_Reduction_By = lifeReductionByData;
context.tbl_Life_Master.Add(entry);
context.SaveChanges();
}
By searching on Stack Overflow, it is clear to me that FirstOrDefault() is the best approach to avoid this execption. But if I want to add multiple records in my list once then what is the solution? As 'getClassFromExcelPivotedValuedreductionBy' here is returning 3 records. Please help me out in this.
But if I want to add multiple records in my list once then what is the solution?
You mean you want to add all the results? Assuming that lifeReductionByData is a List<T> for the appropriate type, you can just use List<T>.AddRange:
var query = classASheet.getClassFromExcelPivotedValuedreductionBy<tbl_Life_Reduction_By>(25, 1, 33, 4, lifeReductionByClassMapper);
lifeReductionByData.AddRange(query);
foreach (var item in lifeReductionByData)
{
item.Class = classesValue[x];
item.UUID = censusSheet.GetValue(25, 27).ToString();
}
Note the use of foreach here instead of the index. Now, if lifeReductionByData was actually empty before this piece of code, and you don't need it afterwards, you can just iterate over the query itself:
var query = classASheet.getClassFromExcelPivotedValuedreductionBy<tbl_Life_Reduction_By>(25, 1, 33, 4, lifeReductionByClassMapper);
foreach (var item in query)
{
item.Class = classesValue[x];
item.UUID = censusSheet.GetValue(25, 27).ToString();
}
If you do need the list afterwards, but it was empty beforehand, then I'd use:
var query = classASheet.getClassFromExcelPivotedValuedreductionBy<tbl_Life_Reduction_By>(25, 1, 33, 4, lifeReductionByClassMapper);
var list = query.ToList();
foreach (var item in list)
{
item.Class = classesValue[x];
item.UUID = censusSheet.GetValue(25, 27).ToString();
}
Next up, I'd rename getClassFromExcelPivotedValuedreductionBy to a) be briefer; b) follow .NET naming conventions.

How to iterate through IEnumerable collection using for each or foreach?

I want to add one by one values but in for loop how can I iterate
through one by one values and add it inside dictionary.
IEnumerable<Customer> items = new Customer[]
{
new Customer { Name = "test1", Id = 111},
new Customer { Name = "test2", Id = 222}
};
I want to add { Name = "test1", Id = 111} when i=0
and want to add { Name = "test2", Id = 222} when i=1 n so on..
Right now i'm adding full collection in every key.(want to achieve this using foreach or forloop)
public async void Set(IEnumerable collection)
{
RedisDictionary<object,IEnumerable <T>> dictionary = new RedisDictionary>(Settings, typeof(T).Name);
// Add collection to dictionary;
for (int i = 0; i < collection.Count(); i++)
{
await dictionary.Set(new[] { new KeyValuePair<object,IEnumerable <T> ( i ,collection) });
}
}
If the count is need and the IEnumerable is to be maintained, then you can try this:
int count = 0;
var enumeratedCollection = collection.GetEnumerator();
while(enumeratedCollection.MoveNext())
{
count++;
await dictionary.Set(new[] { new KeyValuePair<object,T>( count,enumeratedCollection.Current) });
}
New version
var dictionary = items.Zip(Enumerable.Range(1, int.MaxValue - 1), (o, i) => new { Index = i, Customer = (object)o });
By the way, dictionary is a bad name for some variable.
I'm done using
string propertyName = "Id";
Type type = typeof(T);
var prop = type.GetProperty(propertyName);
foreach (var item in collection)
{
await dictionary.Set(new[] { new KeyValuePair<object, T>(prop.GetValue(item, null),item) });
}
So you want to a an item from the collection to the dictionary in the for loop?
If you cast your IEnumerable to a list or an array, you can easily access it via the index. For example like this:
Edit: Code at first created a list every time it looped, which should of course be avoided.
var list = collection.ToList(); //ToArray() also possible
for (int i = 0; i < list.Count(); i++)
{
dictionary.Add(i, list[i]);
}
I'm not 100% if that is what you need, though. More details to your question would be great.

Categories