default values for IEnumerable collection when length is zero - c#

I have a IEnumerable collection:
public IEnumerable<Config> getConfig(string CID, string name)
{
var raw = db.ap_GetInfo(CID, name);
foreach (var item in raw.ToList().Where(x => x.Name!= null))
{
var x = raw.Count();
yield return new Config
{
Name = item.Name.ToString(),
Value = item.Value.ToString(),
};
}
}
The problem I am facing is that if this return a length of zero I am then unable to set the attributes to something else, If I have a response of length 1 the attributes are set from the database, however length zero I want to set a dfault value for Name and Value.

A LINQ solution - this returns the default if there are no items in the enumerable using DefaultIfEmpty:
public IEnumerable<Config> GetConfig(string CID, string name)
{
return db.ap_GetInfo(CID, name)
.Where(x => !string.IsNullOrEmpty(x.Name))
.Select(x => new Config
{
Name = x.Name.ToString(),
Value = x.Value.ToString(),
})
.DefaultIfEmpty(new Config
{
Name = "DefaultName",
Value = "DefaultValue"
});
}

If I understood your question correctly, you want to replace the case
0 results
with
1 result with a default value.
If that is correct, the easiest way is to fix this in the calling function:
var result = getConfig(...).ToList();
if (!result.Any())
{
result = new[] {new Config {Name = "DefaultName", Value = "DefaultValue"}};
}
Obviously, you can wrap this in a new function:
public IEnumerable<ClubConfig> getConfigOrDefault(string CID, string name)
{
var result = getConfig(CID, name).ToList();
if (result.Any())
return result;
else
return new[] {new Config {Name = "DefaultName", Value = "DefaultValue"}};
}

To check if your query did return any elements use Any-method.
public IEnumerable<ClubConfig> getConfig(string CID, string name)
{
var raw = db.ap_GetInfo(CID, name);
if (!raw.Any()) return new[] {
ClubConfig
{
Name = "defaultName",
Value = "defaultValue"
}};
foreach (var item in raw.Where(x => !string.IsNullOrEmpty(x.Name))
{
yield return new ClubConfig
{
Name = item.Name.ToString(),
Value = item.Value.ToString(),
};
}
}
EDIT: You can also omit the ToList from your input.

You can do this using LINQ and can maintain lazy evaluation of the IEnumerable result as follows:
public IEnumerable<ClubConfig> getConfig(string CID, string name)
{
var raw = db.ap_GetInfo(CID, name);
return raw.Where(x => !string.IsNullOrEmpty(x.Name))
.Select(item => new ClubConfig
{
Name = item.Name.ToString(),
Value = item.Value.ToString(),
})
.DefaultIfEmpty(new ClubConfig { Name = "n", Value="v" });
}

Related

LINQ - Condition with .Contains() is not working as expected

I cannot seem to get the desirable filtered result from my query.
Data
public class fdp_1115
{
public string Id{ get; set; }
public string Number{ get; set; }
public string Type{ get; set; }
}
List<fdp_1115> fdpList = new List<fdp_1115>
{
new fdp_1115 { Id = "1", Number = "Lot123", Type = "D14MWT" },
new fdp_1115 { Id = "2", Number = "Lot123", Type = "E12WBC7W1" }
};
List<string> searchValues = new List<string> { "MLE12WBC7W1 A R" };
LINQ:
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => d.Type.Contains(s)));
if (LocType != null)
{
Console.WriteLine("Matching record found:");
Console.WriteLine($"Id: {LocType.Id}, Number: {LocType.Number}, Type: {LocType.Type}");
}
else
{
Console.WriteLine("No matching records found.");
}
The result I wanted is:
Matching record found:
Id: 2, Number: Lot123, Type: E12WBC7W1
But I got "No matching records found." which indicates that LocType == null.
I already tried trimming and ignoring case sensitive:
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => d.Type.Contains(s.Trim().Replace(" ", ""))));
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => d.Type.Contains(s, StringComparison.InvariantCultureIgnoreCase)));
But still no luck. Any idea how do I match "MLE12WBC7W1 A R" with "E12WBC7W1"?
You have your contains the other way around.
d.Type = "E12WBC7W1"
and
s = "MLE12WBC7W1 A R"
Then "E12WBC7W1" does not Contains "MLE12WBC7W1 A R"
It is the other way around.
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => s.Contains(d.Type)));
Your current logic checks whether there is any object with Type value that contains the value for each string in the searchValues array.
From your requirement:
You want to filter the object that fulfills there is any string in searchValues containing the value of Type.
Thus it should be:
var LocType = fdpList.FirstOrDefault(d => searchValues.Any(s => s.Contains(d.Type)));

C# - String to list used in Linq Where Any statement

I would like to use this string as a filter to remove some Ids in a linq query
public class ProductKitMakerDto
{
public int Id { get; set; }
public string TitleShort { get; set; }
public string Media { get; set; }
}
[HttpPost]
public ActionResult KitItemSelect(string culture)
{
string productMakerIds = "4174,2196,2201,2460,2508,2204";
//create a list
var productMakerList = new List<ProductKitMakerDto>();
foreach (int i in productMakerIds)
{
productMakerList.Add(new ProductKitMakerDto { Id = i });
}
var itemselects = (from p in _context.Products
where p.Matrix == 2400
select new ProductKitMakerDto()
{
Id = p.Id,
TitleShort = culture == "de" ? p.TitleShortDe :
culture == "fr" ? p.TitleShortFr :
p.TitleShortEn,
Media = "/img/" + p.Photo,
}).ToList();
//From this query I get 40 results.
//Then I want to remove the ones from the list:
//itemselects = itemselects.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id));
//1st (above) I get an Error CS0266 asking for explicit cast. So aplly the modification
itemselects = (List<ProductKitMakerDto>)itemselects.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id));
return Json(itemselects, JsonRequestBehavior.AllowGet);
}
I get 500 (Internal Server Error) - xhr.send( options.hasContent && options.data || null );
I guess the list is empty.
Any idea? Thanks
this does not work
string productMakerIds = "4174,2196,2201,2460,2508,2204";
var productMakerList = new List<ProductKitMakerDto>();
foreach (int i in productMakerIds)
{
productMakerList.Add(new ProductKitMakerDto { Id = i });
}
because you need to split on comma first and parse the string to int:
foreach (string i in productMakerIds.Split(',')) // and parse i to int with int.Parse
but since it's a string literal, initialize it correctly in the first place. Don't use a List<ProductKitMakerDto> because you just need a List<int>, then you can use Contains:
var productMakerList = new List<int>
{
4174, 2196, 2201, 2460, 2508 , 2204
};
you can not cast to a list if it's not a list and Enumerable.Where does not return one:
itemselects = (List<ProductKitMakerDto>)itemselects.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id));
you need to append ToList after the Where
itemselects = itemselects
.Where(i => !productMakerList.Any(pml =>pml.Id == i.Id))
.ToList();
but as mentioned, you could also use this Where before you create that list the first time, so include the condition witha Contains which should be supported:
var itemselects = (from p in _context.Products
where p.Matrix == 2400
&& !productMakerList.Contains(p.Id)
select new ProductKitMakerDto()
{
Id = p.Id,
TitleShort = culture == "de"
? p.TitleShortDe
: culture == "fr" ? p.TitleShortFr : p.TitleShortEn,
Media = "/img/" + p.Photo,
}).ToList();
foreach (string i in productMakerIds.Split(','))
{
productMakerList.Add(new ProductKitMakerDto { Id = int.Parse(i) });
}

How do i validate and give list of options after first wrong attempt in FormFlow Bot Framework

I am trying to build a bot using bot framework where i want to take string from user for a department name using FormFlow and if user enters wrong department name, I want to validate and give back a list of choices to choose from
DepartmentName string:
[Prompt("What is your department name? {||}")]
public string DepartmentName { get; set; }
Deaprtment name field is as following:
.Field(nameof(DepartmentName),
validate: async (state, response) =>
{
var value = (string)response;
var result = new ValidateResult() { IsValid = false, Feedback = "Department name is not valid"};
if (Enum.GetNames(typeof(Department)).Any(x => x.ToLower() == value))
{
result.IsValid = true;
result.Feedback = null;
result.Value = value;
}
return result;
})
Department enum is as following:
public enum Department
{
hr = 1,
sales,
marketing,
development,
qm
}
How can i prompt user with list of departments in enum if first attempt goes wrong? Thnaks
1) you can just add the options to the end of the Feedback:
.Field(nameof(DepartmentName),
validate: (state, response) =>
{
var value = (string)response;
string[] departments = Enum.GetNames(typeof(Department)).ToArray();
var feedback = $"Department name is not valid. Options:\n\n {String.Join("\n\n", departments)}";
var result = new ValidateResult() { IsValid = false,
Feedback = feedback };
if (departments.Any(x => x.ToLower() == value))
{
result.IsValid = true;
result.Feedback = null;
result.Value = value;
}
return Task.FromResult<ValidateResult>(result);
});
2) you can use the Choice class (normally for disambiguation):
.Field(nameof(DepartmentName),
validate: (state, response) =>
{
var value = (string)response;
string[] departments = Enum.GetNames(typeof(Department)).ToArray();
IEnumerable<Choice> choices = departments.Select(d => new Choice()
{
Description = new DescribeAttribute(d, null, null, null, null),
Terms = new TermsAttribute() { Alternatives = new[] { d } },
Value = d
}).ToArray();
var result = new ValidateResult()
{
IsValid = false,
Choices = choices,
Feedback = "Department name is not valid."
};
if (departments.Any(x => x.ToLower() == value))
{
result.IsValid = true;
result.Feedback = null;
result.Value = value;
}
return Task.FromResult<ValidateResult>(result);
});

Merge two Lists of same type with diff values and avoid duplicates

I have two lists of same type with different key value pairs,
List1 has "isPermanent = true" and List2 has false value and also
List1 has an extra key "nextVacationDate".
Im trying to do union of these as below but im afraid I will still get the duplicates because of different values. I need to merge both lists in to one list and order by List1 first (Permanent employees first)..is there a better way to do this using LINQ?
public newList1 List1(string abcd)
{
var result = serviceMethod1(abcd);
var newList1 = new List<emp>();
if (result == null) return null;
newList.AddRange(
result.Select(x => new Model
{
firstName = x.FName,
secondName = x.SName,
address = x.Address,
employeeId = x.EmpId,
isPermanent = true,
nextVacationDate =x.VacDt,
salary = x.Bsalary
}));
return newList1;
}
public newList2 List2(string defg)
{
var result = serviceMethod2(defg);
var newList2 = new List<emp>();
if (result == null) return null;
newList.AddRange(
result.Select(x => new Model
{
firstName = x.FName,
secondName = x.SName,
address = x.Address,
employeeId = x.EmpId,
isPermanent = false,
salary = x.Bsalary
}));
return newList2;
}
private List<emp> EmployyeList(List<emp> newList1, List<emp> newList2)
{
var sortedEmpList1 = newList1.OrderBy(i => i.Fname);
var sortedEmpList2 = newList2.OrderBy(i => i.Fname);
List<MeterModel> combinedList = newList1.Union(newList2) as List<emp>;
return combinedList;
}
You can filter the 2nd list to avoid duplicates:
newList1.Union(newList2.Where(emp2 => !newList1.Any(emp1 => emp1.employeeId == emp2.employeeId)))

Not Returning properly

I was trying to get employee list which not already available in another list. but im getting only first element from array list.
ex : if i try EmployeeId = new int[2] {5, 2}; the list excluding only '5'. So please help me correct my below code.
public JsonResult GetEmployees(int[] EmployeeId)
{
var dbs = new dbContext();
if (EmployeeId != null)
{
foreach (var emp in EmployeeId)
{
var EmpList = dbs.Employees.Select(e => new
{
EmployeeId = e.EmployeeId,
Name = e.EmployeeName,
Job = e.Job.JobName,
Currency = e.Currency.CurrencyName,
Amount = e.Amount
}).Where(o => o.EmployeeId != emp);
return Json(EmpList, JsonRequestBehavior.AllowGet);
}
}
return null
}
Try this :
var employeeList = dbs.Employees.
.Where(e => EmployeeId.All(x=> x != e.EmployeeId))
.Select(e => new
{
EmployeeId = e.EmployeeId,
Name = e.EmployeeName,
Job = e.Job.JobName,
Currency = e.Currency.CurrencyName,
Amount = e.Amount
});
return Json(EmpList, JsonRequestBehavior.AllowGet);
}
Have you tried stepping through your code?
Your foreach iterates over your EmployeeId array.
Since you have a return statement in your foreach it exits the function at that point and it only uses the first element of your array.
You need something like this:
public JsonResult GetEmployees(int[] EmployeeId)
{
var dbs = new dbContext();
if (EmployeeId != null)
{
var EmpList = dbs.Employees.Where(EmployeeId.Contains(e.EmployeeId))
.Select(e => new
{
EmployeeId = e.EmployeeId,
Name = e.EmployeeName,
Job = e.Job.JobName,
Currency = e.Currency.CurrencyName,
Amount = e.Amount
}).Where(o => o.EmployeeId != emp);
return Json(EmpList, JsonRequestBehavior.AllowGet);
}
return null;
}

Categories

Resources