Combine two Lists C# does not exist in current context - c#

In c# I have 2 lists.
First List is like so:
respondent.PrescreenerResponses[i].Response[j] = {[12, some response]}
Second List is like so:
projects.Prescreeners[i].Questions[j] = {Prescreener Questions: Question}
What I want to do is create one list probably like:
Prescreeners[i].Responses[j]
Prescreeners[i].Questions[j]
My code though is somehow wrong:
foreach (var screener in respondent.PreScreenerResponses)
{
var responses = screener;
}
foreach (var screener in project.PreScreeners)
{
var questions = screener;
}
List<string> prescreenerResponses = new List<string>();
prescreenerResponses.Add(questions);
It tells me questions does not exist in the current context. Same goes for responses when I try to use it. I am pretty sure it the wrong data type but not sure what else it would be?

I am pretty sure it the wrong data type
No, it's scope. You declare the var responses and var questions in their respective foreach block. As soon as control leaves those blocks, the variables don't exist anymore.
Declare them first:
IEnumerable<PrescreenerResponses> responses = new List<PrescreenerResponses>;
foreach (...)
{
responses.Add(...)
}
Anyway you can also call AddRange() if you declase responses as List, so you can skip the loop:
responses.AddRange(respondent.PreScreenerResponses);
And it's even more advisable to create a DTO:
class QuestionAndAnswer
{
public PreScreener Question { get; set; }
public PreScreenerResponse Response { get; set; }
}
And use a loop with a counter to fill a List<QuestionAndAnswer>:
var result = new List<QuestionAndAnswer>();
for (int i = 0; i < projects.Prescreeners.Count; i++)
{
result.Add(new QuestionAndAnswer
{
Question = projects.Prescreeners[i],
Answer = respondent.PrescreenerResponses[i],
});
}

Try it like this
List<string> prescreenerResponses = new List<string>();
foreach (var screener in respondent.PreScreenerResponses)
{
var responses = screener;
}
foreach (var screener in project.PreScreeners)
{
prescreenerResponses.Add(screener);
}

You are accessing variable "questions" which is declared outside the scope,
Try this:
List<string> prescreenerResponses = new List<string>();
foreach (var screener in respondent.PreScreenerResponses)
{
var responses = screener;
}
foreach (var screener in project.PreScreeners)
{
var questions = screener;
prescreenerResponses.Add(questions);
}

It´s because 'questions' is declared inside your loop. You could try the code below:
private class QuestionAndResponses
{
public List<Response> Responses {get;set;}
public List<Question> Questions {get;set;}
}
List<QuestionAndResponses> prescreenerResponses = new List<QuestionAndResponses>();
for (var i = 0; i < project.preScreeners.Count(); i++)
{
prescreenerResponses.Add(new QuestionAndResponses ()
{
Responses = new List<Response>(project.preScreenerResponses[i].Response),
Questions = new List<Question>(project.preScreeners[i].Questions)
});
}

Related

GROUP BY to List<> with Linq

I'm new to using Linq so I don't understand some things or its syntax. I want to group a list and then loop through it with foreach, like my logic below. Obviously my logic doesn't work.
My code:
var final = finalv.Union(finalc);
final = final.GroupBy(x => x.Clave);
foreach (var articulo in final)
{
Articulo articulo2 = new Articulo();
articulo2.ArtID = articulo.ArtID;
articulo2.Clave = articulo.Clave;
articulo2.ClaveAlterna = articulo.ClaveAlterna;
lista.Add(articulo2);
}
First, such usage is syntactically consistent with this overloaded method of GroupBy: GroupBy<TSource,TKey>(IEnumerable<TSource>, Func<TSource,TKey>), and it will return a IEnumerable<IGrouping<TKey,TSource>> variable.
That means, if you run final.GroupBy(x => x.Clave), let's assume he returns finalWithGrouped, then finalWithGrouped.Key is the key and finalWithGrouped.ToList() is a collection of all variables with the same key(at here, it is with the same Clave).
And for your code, try this:
var final = finalv.Union(finalc);
var finalWithGrouped = final.GroupBy(x => x.Clave);
foreach (var articulosWithSameClavePair in finalWithGrouped)
{
var clave = articulosWithSameClavePair.Key;
var articulos = articulosWithSameClavePair.ToList();
foreach(var articulo in articulos)
{
Articulo articulo2 = new Articulo();
articulo2.ArtID = articulo.ArtID;
articulo2.Clave = articulo.Clave;
articulo2.ClaveAlterna = articulo.ClaveAlterna;
lista.Add(articulo2);
}
}
I suggest you read some examples of using GroupBy.
When you group a list, it will return a key and groued list and you are trying reach a single property of a list.
When you group an data, you can convert it to dictionary, It is not nessesary but better way for me. You can try this code:
var final = finalv.Union(finalc);
final = final.GroupBy(x => x.Clave).ToDictionary(s=> s.Key, s=> s.ToList();
foreach (var articulo in final)
{
foreach (var articuloItem in articulo.value)
{
Articulo articulo2 = new Articulo();
articulo2.ArtID = articuloItem.ArtID;
articulo2.Clave = articuloItem.Clave;
articulo2.ClaveAlterna = articuloItem.ClaveAlterna;
lista.Add(articulo2);
}
}

If statement with multiple variables ending with a number [duplicate]

This question already has answers here:
How do I check for null or empty string for many arguments? - C#
(5 answers)
Closed 2 years ago.
Variables:
private string filePath1 = null;
private string filePath2 = null;
private string filePath3 = null;
private string filePath4 = null;
private string filePath5 = null;
private string filePath6 = null;
private string filePath7 = null;
private string filePath8 = null;
private string filePath9 = null;
private string filePath10 = null;
Current If statement
if (string.IsNullOrEmpty(filePath1))
{
errors.Add("File Not Attached");
}
if (string.IsNullOrEmpty(filePath2))
{
errors.Add("File Not Attached");
}
....
Question:
Instead of having multiple if statements, for each variable. How can I create 1 if statement to go through all these variables?
Something like this:
if (string.IsNullOrEmpty(filePath + range(1 to 10))
{
errors.Add("File Not Attached");
}
You can achieve this using Reflection. This is obviously discouraged for this scenario, as the other answers provide better solutions, just wanted to show you it's doable the way you intended it to be done (which doesn't mean it's the correct way)
public class Test
{
private string filePath1 = null;
private string filePath2 = null;
private string filePath3 = null;
}
Usage:
Test obj = new Test();
//loop through the private fields of our class
foreach (var fld in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.Name.StartsWith("filePath"))) // filter
{
if (string.IsNullOrEmpty(fld.GetValue(obj) as string))
{
errors.Add("File Not Attached in variable: " + fld.Name);
}
}
In nearly all cases where you're using variables with a differently numbered suffix, you should really be using a collection (array, list, ...). This is one of those cases. I'll be using a list for this answer but any collection will suffice.
private List<string> filePaths = new List<string>()
{
"path1",
"path2",
"path3",
"path4"
};
You can then use a loop to iterate over your list:
foreach (string path in filePaths)
{
if(String.IsNullOrEmpty(path))
errors.Add("File not attached");
}
Create a new arraylist, add all file paths to it (or initialise it with all filepaths) and the loop over the elements in the array (using for-each loop). For each element, check if nullOrEmpty and if yes add to your errors string.
ArrayList arrlist = new ArrayList();
arrList.add(filePath1);
arrList.add(filePath2);
arrList.add(filePath3);
arrList.add(filePath4);
arrList.add(filePath5);
arrList.add(filePath6);
arrList.add(filePath7);
arrList.add(filePath8);
arrList.add(filePath9);
arrList.add(filePath10);
foreach (string element in arrList)
{
if (string.IsNullOrEmpty(element)
{
errors.Add("File Not Attached");
}
}
ps. You might want to print a new line after each error:
errors.Add("File Not Attached\n");
// Create list
List<string> filePaths = new List<string>;
//Add path in list like
filePaths.add(filePath1);
//Check for null path here
foreach (string filepath in filePaths)
{
if (string.IsNullOrEmpty(filepath)
{
errors.Add("File Not Attached");
}
}
In order to treat all strings the same way they have to be in some collection.
using System.Linq;
...
string[] allPaths = new string[10];
// Do something with these ten paths...
if (allPaths.Any(x => string.IsNullOrEmpty(x))
errors.Add("File Not Attached");
As stated every other answers, you should use a collection.
If you really want to stick with fields names, you can use reflection, but I strongly recommend to use collections over reflection :
// using System.Reflection;
// Below code is meant to be used in a method of the class that holds the fields.
for (int i = 1; i <= 10; i++)
{
if (string.IsNullOrEmpty(this.GetType()
.GetField($"filePath{i}",
BindingFlags.NonPublic | BindingFlags.Instance)?
.GetValue(this))
{
errors.Add("File Not Attached");
}
}
If you can make those variable class fields i would vote for Innat3's Answer.
Bu if this is not possible and you can't make those variables class fields then i suggest to you do like following :
class Program
{
static void Main(string[] args)
{
Dictionary<string, int> names = new Dictionary<string,int>();
for (int i = 0; i < 10; i++)
{
names.Add(String.Format("name{0}", i.ToString()), i);
}
var xx1 = names["name1"];
var xx2 = names["name2"];
var xx3 = names["name3"];
}
}
Because in c# we can't compute dynamically variable names.
Hope this helps.

How can I ensure rows are not loaded twice with EF / LINQ

I created code to load definitions from an external API. The code iterates through a list of words, looks up a definition for each and then I thought to use EF to insert these into my SQL Server database.
However if I run this twice it will load the same definitions the second time. Is there a way that I could make it so that EF does not add the row if it already exists?
public IHttpActionResult LoadDefinitions()
{
var words = db.Words
.AsNoTracking()
.ToList();
foreach (var word in words)
{
HttpResponse<string> response = Unirest.get("https://wordsapiv1.p.mashape.com/words/" + word)
.header("X-Mashape-Key", "xxxx")
.header("Accept", "application/json")
.asJson<string>();
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(response.Body);
var results = rootObject.results;
foreach (var result in results)
{
var definition = new WordDefinition()
{
WordId = word.WordId,
Definition = result.definition
};
db.WordDefinitions.Add(definition);
}
db.SaveChanges();
}
return Ok();
}
Also would appreciate if anyone has any suggestions as to how I could better implement this loading.
foreach (var result in results)
{
if(!(from d in db.WordDefinitions where d.Definition == result.definition select d).Any())
{
var definition = new WordDefinition()
{
WordId = word.WordId,
Definition = result.definition
};
db.WordDefinitions.Add(definition);
}
}
You can search for Definition value.
var wd = db.WordDefinition.FirstOrDefault(x => x.Definition == result.definition);
if(wd == null) {
var definition = new WordDefinition() {
WordId = word.WordId,
Definition = result.definition
};
db.WordDefinitions.Add(definition);
}
In this way you can get a WordDefinition that already have your value.
If you can also use WordId in the same way:
var wd = db.WordDefinition.FirstOrDefault(x => x.WordId == word.WordId);

Argument Exception “Item with Same Key has already been added” in thread

I have a method that is called by thread. I am having problem with the dictionary that item already exist exception. what could be the possible solution. i have provided my scenario code and changes made to overcome the problem.
The method is called by the thread.
public Item[] GetFolders()
{
Dictionary<long,string> values = new Dictionary<long,string> ();
Dictionary<long,string> values2 = new Dictionary<long,string> ();
var remotePage = service.GetPage();
foreach(var remotesummary in remotePage)
{
values2.Add(remotesummary.id, remotesummary.name);
}
foreach(var remotesummary in remotePage)
{
values.Add(remotesummary.id, remotesummary.name);
}
}
Modified code to overcome the exception ""
public Item[] GetFolders()
{
Dictionary<long,string> values = new Dictionary<long,string> ();
Dictionary<long,string> values2 = new Dictionary<long,string> ();
foreach(var remotesummary in remotePage)
{
var remt = remotesummary;
values.Add(remotesummary.id, remotesummary.name);
}
foreach(var remotesummary in remotePage)
{
var remt = remotesummary;
values2.Add(rem.id, rem.name);
}
}
You can check if that key already exists before inserting it. Add this to your code
if (dict.ContainsKey(key)) { ... }
plase note that you need to change dict for your variable name :D

ArgumentOutOfRangeException when writing to a model

I'm trying to write to a model for the first time to use in my view: the first time I write to the model I get an ArgumentOutOfRangeException.
Getting error on first write to array:
private IAdditionalQuestionsService _service;
private SelectedAdditionalQuestionAnswerModel _model;
private void InitializeController()
{
_service = GetObject<IAdditionalQuestionsService>();
//GetPageHeaderText(inst);
ViewBag.GetPageTitle = "Additional Questions";
}
[HttpGet]
public virtual ActionResult Edit()
{
Institution inst = _service.GetInstitution(State.GetInstitutionRecordId());
_model = GetObject<SelectedAdditionalQuestionAnswerModel>();
_model.AddQuestAnswModel = new List<AdditionalQuestionAnswerModel>();
GetPageConfiguration1(inst);
return View(_model);
}
AdditionalQuestionAnswerModel m = GetObject<AdditionalQuestionAnswerModel>();
int c = 0;
foreach (var x in inst.AdditionalQuestions)
{
foreach (var y in x.AdditionalQuestionAnswers)
{
// Error is happening on next line *************
_model.AddQuestAnswModel[c].QuestionText = x.QuestionText;
_model.AddQuestAnswModel[c].InstitutionId = x.InstitutionId;
_model.AddQuestAnswModel[c].AdditionalQuestionId = x.Id;
_model.AddQuestAnswModel[c].AnswerText = y.AnswerText;
_model.AddQuestAnswModel[c].IsSelected = false;
c++;
}
}
You can't use _model.AddQuestAnswModel[c] because you never added any items to your list.
Instead of that, create a new object and set its values and then add the item to your list.
Something like this:
AdditionalQuestionAnswerModel newItem = new AdditionalQuestionAnswerModel();
//set the values here to newItem
_model.AddQuestAnswModel.Add(newItem);
You're firstly instantiating your list
_model.AddQuestAnswModel = new List<AdditionalQuestionAnswerModel>();
then you try to access to the first element
_model.AddQuestAnswModel[c] // c == 0
without adding any element to the list.
Add an element before trying to access to a list by index, or more simple:
foreach (var y in x.AdditionalQuestionAnswers)
{
AdditionalQuestionAnswerModel newObj = new AdditionalQuestionAnswerModel
{
QuestionText = x.QuestionText;
InstitutionId = x.InstitutionId;
AdditionalQuestionId = x.Id;
AnswerText = y.AnswerText;
IsSelected = false;
};
_model.AddQuestAnswModel.Add(newObj);
}
Ir means that there no item in your _model.AddQuestAnswModel at the indicated postition, and from your code, I see that _model.AddQuestAnswModel has only be initiated with new List<AdditionalQuestionAnswerModel>(), so it does not contain items (unless you're doing it in the contructor).
You need to fill it like so :
_model.AddQuestAnswModel.Add(item);

Categories

Resources