select case in Datatable datarow in Linq - c#

I have a DataTable which is having 3 columns like IsMonday,Istuesday and IsWednesday,both are string fields having datas like Y and N.I wanted to take each row and return the result in a string.What i wanted to get is,
if a row is Y,N,Y then the output will be 1 3,two is blank since it is N
if a row is N,N,Y then the output will be 3,one and two is blank since it is N
like this,any idea using Linq case statement or any other way

Considering that you have a collection of rows returned from your database that looks something similar to this List.
var entity = new List<Entity>()
{
new Entity(){ IsMonday = "Y", IsTuesday = "N", IsWednesday = "Y"},
new Entity() { IsMonday = "N", IsTuesday = "N", IsWednesday = "Y"},
new Entity() { IsMonday = "Y", IsTuesday = "Y", IsWednesday = "N"}
};
To get the expected result you can use a code something like this
foreach (var e in entity)
{
var a = e.IsMonday.Equals("y", StringComparison.OrdinalIgnoreCase) ? "1" : " ";
var b = e.IsTuesday.Equals("y", StringComparison.OrdinalIgnoreCase) ? "2" : " ";
var c = e.IsWednesday.Equals("y", StringComparison.OrdinalIgnoreCase) ? "3" : " ";
var s = String.Format("{0} {1} {2}", a, b, c);
}
Here the variable 's' contains the result string.

This will turn all the rows into List<string>:
var columnNames = new[]{"IsMonday","Istuesday","IsWednesday"};
var rows = dt.AsEnumerable()
.Select(row=>string.Join("",
dt.Columns.Cast<DataColumn>()
.Where(col=>columnNames.Contains(col.ColumnName))
.Select(col=>row.Field<string>(col) == "N" ? " " :
(col.Ordinal+1).ToString()))).ToList();
Note that you said something like that "N" will be replaced with a blank, but looks like you mean a space, so I used a space instead, you can just replace it to whatever you want.
If you just want to convert a specific row to a string, it's very similar like this:
//the input is row
var rowString = string.Join("",
dt.Columns.Cast<DataColumn>()
.Where(col=>columnNames.Contains(col.ColumnName))
.Select(col=>row.Field<string>(col) == "N" ? " " :
(col.Ordinal+1).ToString())).ToList();

Related

Splitting text into an array of 4

I want to split text, using a char, so that I can create an object from it.
string s = "Domain_FieldName";
//string s = "Domain_Schema_TableName_FieldName";
//string s = "Domain_Schema_FieldName";
var x = s.Split(new[] {'_'}, StringSplitOptions.None);
var xx = new Response()
{
Value = "test",
DataType = "string",
Domain =
Schema =
TableName =
FieldName =
};
So, the issue is that the string to be split, could vary in length.
But I need the string to be split so that it could map to the response object fields.
I need to have a generic way to populate the response object.
So as an example, if only "Domain_FieldName" is specified, it needs to know to pass Domain to Domain on the response and FieldName to FieldName on the response, and Schema and TableName should get an empty string
You can do something like this:
var x = s.Split(new[] { '_' }, StringSplitOptions.None);
var xx = new Response
{
Value = "test",
DataType = "string",
Domain = x.Length > 0 ? x[0] : null,
Schema = x.Length > 1 ? x[1] : null,
TableName = x.Length > 2 ? x[2] : null,
FieldName = x.Length > 3 ? x[3] : null
};
Use C# Split function
string s = "Domain_Schema_TableName_FieldName";
string[] substring= s.Split('_');
The above code will split the string Domain_Schema_TableName_FieldName into different parts using the delimiter _ and will save the substrings in a string array called substring
Try checking the length of the split Array, before setting variables. (And set a default value, if it's too short)
var xx = new Response()
{
Value = "test";
DataType = "string";
Domain = (x.Length >= 1)?x[0]:"";
Schema = (x.Length >= 2)?x[1]:"";
TableName = (x.Length >= 3)?x[2]:"";
FieldName = (x.Length >= 4)?x[3]:"";
};
(also: s.Split("_") or s.Split('_') would work just as well)
EDIT:
I didn't see, that you only wanted the last 4 fields filled. Changed code
2nd EDIT:
I also didn't see that the Order of strings may be different (i.e. Example 1 vs. Example 3) . In that case i can't help you unless you can specify, how to determine which string needs to go into which field.
try this
string s = "Domain_FieldName";
var x = s.Split(new[] { '_' }, StringSplitOptions.None);
var xx = new Response
{
Value = "test",
DataType = "string",
Domain =x[0],
Schema ="",
TableName ="",
FieldName = x[1]
};
From your examples seems like Domain is always first, and FieldName always last:
string s = "Domain_FieldName";
//string s = "Domain_Schema_TableName_FieldName";
//string s = "Domain_Schema_FieldName";
var x = s.Split('_');
var xx = new Response()
{
Value = "test",
DataType = "string",
Domain = x[0]
Schema = x.Length > 2 ? x[1] : "";
TableName = x.Length > 3 ? x[2] : "";
FieldName = x.Length > 1 ? x.Last() : "";
};

Retrieve the name of the column from which the values where chosen in C#

I have a form which has 4 columns say Col1,Col2,Col2,Col4...
Each Column has a combo box (cmb1,cmb2,cmb3,cmb4) having values ranged from 1 to 3.
If I select value of cmb1 as 1,
cmb2 as 2,
cmb3 as 3,
cmb4 as 2 ....
I need to know which column had 1 as value,2 as value and 3 .
here the result should be like
Col1 has 1 value ,
Col2 and Col4 has 2 value and
Col3 has 3 value
Following is my code :
if (cmb1 == "1" && cmb2 == "1" && cmb3 == "1" && cmb4 == "1")
{
Console.WriteLine("Col1,Col2,Col3,Col4");
}
if (cmb1 == "1" && cmb2 == "1" && cmb3 == "1")
{
Console.WriteLine("Col1,Col2,Col3");
}
if (cmb1 == "2" && cmb2 == "2" )
{
Console.WriteLine("Col1,Col2");
}
This code is too lengthy .Which is the best way with minimum lines of code.
You can group by the value, then select the column name by Linq.
For display you can use string.Join().
var cmb1 = "1";
var cmb2 = "2";
var cmb3 = "3";
var cmb4 = "2";
var selection = new Dictionary<string, string>()
{
{"Col1", cmb1},
{"Col2", cmb2},
{"Col3", cmb3},
{"Col4", cmb4},
};
var result = selection
.GroupBy(i => i.Value) // Group by your combo box values
.Select(group =>
new
{
Value = group.Key,
Columns = group.Select(i => i.Key).ToArray()
}
);
foreach (var item in result) // for each value in your combo box
{
Console.WriteLine(
string.Format("Value: {0}, Columns: {1}",
item.Value,
string.Join(",", item.Columns)));
string[] column = item.Columns; // It should store somewhere else, line for demo only
}
ComboBox has property named SelectedItem, you can get the selectedvalue due to SelectedItem.And set the Name of Combox.
List<Combox> comboxs = new List<Combox>;
comboxs.Add(cmb1);
comboxs.Add(cmb2);
comboxs.Add(cmb3);
comboxs.Add(cmb4);
foreach(var combox in comboxs){
Console.WriteLine(combox.Name + "has" + combox.SelectedItem + "value");
}

Tricky LINQ query for text file format transformation

I have a shopping list in a text file, like this:
BuyerId Item;
1; Item1;
1; Item2;
1; ItemN;
2; Item1;
2; ItemN;
3; ItemN;
I need to transform this list to a format like this:
Item1; Item2; Item3; ...; ItemN <--- For buyer 1
Item1; ...; ItemN <--- For buyer 2
Item1; ...; ItemN <--- For buyer 3
First I parse the CSV file like this:
IList<string[]> parsedcsv = (from line in lines.Skip(1)
let parsedLine = line.TrimEnd(';').Split(';')
select parsedLine).ToList();
Then I group the items with LINQ and aggregate them to the final format:
IEnumerable<string> buyers = from entry in parsedcsv
group entry by entry[0] into cart
select cart.SelectMany(c => c.Skip(1))
.Aggregate((item1, item2) =>
item1 + ";" + item2).Trim();
HOWEVER, as it happens, the BuyerId is not unique, but repeats after a number of times (for example, it can repeat like this: 1,2,3,4,5,1,2,3,4,5,1,2,3 or like this 1,2,3,1,2,3,1,2).
No big deal, I could quite easily fix this by grouping the items in a loop that checks that I only deal with one buyer at a time:
int lastBatchId = 0;
string currentId = parsedcsv[0][0];
for (int i = 0; i < parsedcsv.Count; i++)
{
bool last = parsedcsv.Count - 1 == i;
if (parsedcsv[i][0] != currentId || last)
{
IEnumerable<string> buyers = from entry in parsedcsv.Skip(lastBatchId)
.Take(i - lastBatchId + (last ? 1 : 0))
...
lastBatchId = i;
currentId = parsedcsv[i][0];
...
... however, this is not the most elegant solution. I'm almost certain this can be done only with LINQ.
Can anyone help me out here please ?
Thanks!
You should have a look at GroupAdjacent.
I'm not sure this is the best solution, but you said you want a pure Linq answer, so here you have it:
var result = from r in (
from l in lines.Skip(1)
let data = l.Split(new string[]{";"," "},
StringSplitOptions.RemoveEmptyEntries)
select new { Id = data.First(), Item = data.Skip(1).First() })
.Aggregate(new
{
Rows = Enumerable.Repeat(new
{
Id = string.Empty,
Items = new List<string>()
}, 1).ToList(),
LastID = new List<string>() { "" }
},
(acc, x) =>
{
if (acc.Rows[0].Id == string.Empty)
acc.Rows.Clear();
if (acc.LastID[0] != x.Id)
acc.Rows.Add(new
{
Id = x.Id,
Items = new List<string>()
});
acc.Rows.Last().Items.Add(x.Item);
acc.LastID[0] = x.Id;
return acc;
}
).Rows
select new
{
r.Id,
Items = string.Join(";", from x in r.Items
select x)
};
I wrote it pretty fast and it could be improved, I don't like it particularly because it resorts to a couple of tricks, but it's pure Linq and could be a starting point.

How to use LINQ select something contain string[]

How to use linq to select something fit the conditions below,
I want select the words JUST contains the string in ArStr[], i.e. a,b,c
In the Wordslist, "aabb" don't contain "c", "aacc" don't contain "b", "aabbccd" contain "d".
So they are not the words I want.
Please help.
Wordslist :
aabb
aacc
aaabbcc
aabbbcc
aabbccd
ArStr[] :
"a"
"b"
"c"
Expected Query:
aaabbcc
aabbbcc
IEnumerable<Word> Query =
from Word in Wordslist
where
Word.Value.Contains(ArStr[0]) // 1
&& Word.Value.Contains(ArStr[1]) // 2
&& Word.Value.Contains(ArStr[2]) // 3
select Word;
You can construct a set of white-list characters and then filter those words that are set-equal with that white-list (ignoring duplicates and order).
var chars = new HashSet<char>(ArStr); // Construct white-list set
var query = from word in wordsList
where chars.SetEquals(word) // Word must be set-equal with white-list
select word;
or
var query = wordsList.Where(chars.SetEquals);
As you've probably noticed, the query you've written does return "aabbccd", because that string contain "a", it contains "b", and it contains "c".
Assuming that ArStr can only contain one-character strings, and you want to return strings that contain only the specified characters, so you should say (adapted from Ani's answer):
var chars = new HashSet<char>(ArStr.Select(s => s[0]));
var query = wordslist.Where(w => chars.SetEquals(w.Value));
However, if the ArStr elements could be more than one character long, the problem needs to be better defined, and the solution will be more complicated.
Use this method to evaluate a word if it passes your condition or not:
bool HasValidCharacters(string word)
{
var allowedCharacters = new List<string> { "a", "b", "c" };
return string.Join("", word.GroupBy(c => c)
.Select(g => g.Key)
.OrderBy(g => g))
.Equals(string.Join("", allowedCharacters.OrderBy(c => c)));
}
Then simply call the method to get the required list:
var words = new List<string> { "aabb", "aacc", "aaabbcc", "aabbbcc", "aabbccd" };
var matchingWords = words.Where(HasValidCharacters);
You could try this:
List<String> words = new List<string> { "aabb", "aacc", "aaabbcc", "aabbbcc", "aabbccd" };
List<string> allowed = new List<string> { "a", "b", "c" };
var lst = words.Where(word => allowed.All(a => word.Contains(a) && !Regex.IsMatch(word, "[^" + string.Join("", allowed) + "]"))).ToList();
Just another way to implement it.
I think you can use String.Trim Method (Char()) on each element , then the empty element is you want .
var arr = new string[] { "aabb", "aacc", "aaabbcc", "aabbbcc", "aabbccd" };
var arStr = new string[] { "a", "b", "c" };
var str = string.Join("", arStr);
var result = from p in arr
let arCharL = arStr.Select(a => Convert.ToChar(a)).ToArray()
let arCharR = p.ToCharArray()
where p.Trim(arCharL).Length == 0 && str.Trim(arCharR).Length == 0
select p;

How to filter a jagged array by using the where function

I have a jagged array that looks like this:
string[][] list = new string[d.Rows.Count + 1][];
int c = 0;
while (c < d.Rows.Count)
{
list[c] = new string[]
{
d.Rows[c].ItemArray[2].ToString(),
d.Rows[c].ItemArray[1].ToString(),
d.Rows[c].ItemArray[4].ToString(),
d.Rows[c].ItemArray[5].ToString(),
d.Rows[c].ItemArray[7].ToString(),
d.Rows[c].ItemArray[3].ToString(),
d.Rows[c].ItemArray[14].ToString()
};
c += 1;
}
return list;
Now, for a new requirement, i need only the items from this array whose value at this location: list[x][0] are equal to any of the following strings: "Text", "FullText", "FullMatch"
I got started with a regular array i could do this: but it obvioulsy won't work for a jagged array.
string[][] newlist = list.where(item => item.equals("Text");
Does any one know how to extend this for my situation?
You can do a where on list which will iterate over each one-dimensional array, then compare element 0 to the strings given.
string[][] newlist = list
.Where(item => item[0].Equals("Text")
|| item[0].Equals("FullText")
|| item[0].Equals("FullMatch"))
.ToArray();
Tested this on some sample data as shown below:
var list = new string[][]
{
new string[] { "Text", "A", "B", "C", "D" },
new string[] { "None", "Z", "C" },
new string[] { "FullText", "1", "2", "3" },
new string[] { "FullMatch", "0", "A", "C", "Z" },
new string[] { "Ooops", "Nothing", "Here" },
};
string[][] newlist = list.Where(item => item[0].Equals("Text")
|| item[0].Equals("FullText")
|| item[0].Equals("FullMatch")).ToArray();
// now display all data...
foreach (string[] row in newlist)
{
Console.Write("Row: ");
foreach (string item in row)
{
Console.Write(item + " ");
}
Console.WriteLine();
}
This worked correctly with output being:
Row: Text A B C D
Row: FullText 1 2 3
Row: FullMatch 0 A C Z
If you wanted a fully LINQ-based solution, then I think the following should do the trick (although I haven't tested it, because I'm not usre what the variable d refers to):
var res =
(from c in Enumerable.Range(0, d.Rows.Count)
let list = new string[] {
d.Rows[c].ItemArray[2].ToString(),
d.Rows[c].ItemArray[1].ToString(),
d.Rows[c].ItemArray[4].ToString(),
d.Rows[c].ItemArray[5].ToString(),
d.Rows[c].ItemArray[7].ToString(),
d.Rows[c].ItemArray[3].ToString(),
d.Rows[c].ItemArray[14].ToString()
}
where list[0] == "Text" || list[0] == "FullText" || list[0] == "FullMatch"
select list).ToArray();
A jagged array is just an array of arrays, so you can process it using LINQ. The only trick is that individual items will be arrays (representing your columns). After using Where, you can turn the result back to an array using ToArray:
string[][] newlist = list.Where(item => item[0] == "Text" || ... ).ToArray();

Categories

Resources