read text file and writing to a list - c#

Is their a way to split a text file in multiple places all at once and save to a list?
I was able to do the split in one place and write to a list like this:
var incomplete = File
.ReadAllLines(path)
.Select(a => a.Split(new[] { '|' }, StringSplitOptions.None)[5].Trim())
.ToList();
I would like to split in four locations and then write to a list.
var mnbrs = File
.ReadAllLines(path)
.Select(a => a.Split('|')[2].Trim())
.Select(b => b.Split('|')[5].Trim())
.Select(c => c.Split('|')[6].Trim())
.Select(d => d.Split('|')[11].Trim())
.ToList();
this gives me error index was outside of bounds of array.
Any help is appreciated.
Am also open to split and read filing in a different manner as well.
I just would like to avoid reading file split once then to list then reading agian and splitting again and doing it four times.

You want to do it in two steps. First split, then select the individual columns:
File
.ReadAllLines(path)
.Select(a => a.Split(new[] { '|' }, StringSplitOptions.None))
.Select(a => new {
Column1 = a[2].Trim(),
Column2 = a[5].Trim(),
Column3 = a[6].Trim(),
Column4 = a[11].Trim()
})
.ToList();
Demo: http://ideone.com/aNyNT5

Related

How to modify string list for duplicate values?

I am working on project which is asp.net mvc core. I want to replace string list of duplicate values to one with comma separated,
List<string> stringList = surveylist.Split('&').ToList();
I have string list
This generate following output:
7=55
6=33
5=MCC
4=GHI
3=ABC
1003=DEF
1003=ABC
1=JKL
And I want to change output like this
7=55
6=33
5=MCC
4=GHI
3=ABC
1003=DEF,ABC
1=JKL
Duplicate items values should be comma separated.
There are probably 20 ways to do this. One simple one would be:
List<string> newStringList = stringList
.Select(a => new { KeyValue = a.Split("=") })
.GroupBy(a => a.KeyValue[0])
.Select(a => $"{a.Select(x => x.KeyValue[0]).First()}={string.Join(",", a.Select(x => x.KeyValue[1]))}")
.ToList();
Take a look at your output. Notice that an equal sign separates each string into a key-value pair. Think about how you want to approach this problem. Is a list of strings really the structure you want to build on? You could take a different approach and use a list of KeyValuePairs or a Dictionary instead.
If you really need to do it with a List, then look at the methods LINQ's Enumerable has to offer. Namely Select and GroupBy.
You can use Select to split once more on the equal sign: .Select(s => s.Split('=')).
You can use GroupBy to group values by a key: .GroupBy(pair => pair[0]).
To join it back to a string, you can use a Select again.
An end result could look something like this:
List<string> stringList = values.Split('&')
.Select(s => {
string[] pair = s.Split('=');
return new { Key = pair[0], Value = pair[1] };
})
.GroupBy(pair => pair.Key)
.Select(g => string.Concat(
g.Key,
'=',
string.Join(
", ",
g.Select(pair => pair.Value)
)
))
.ToList();
The group contains pairs so you need to select the value of each pair and join them into a string.

Filtering and combining data in an array

I have an array:
{"Items":[
{"folder":"Test","number":"11"},
{"folder":"Test","number":"10"},
{"folder":"Test1","number":"130"},
{"folder":"Test1","number":"100"},
{"folder":"Test2","number":""},
{"folder":"Test2","number":"200"}
]}
Tell me I need to make it so that the folder is unique, and write its values in number separated by commas?
{"Items":[
{"folder":"Test","number":"11, 10"},
{"folder":"Test1","number":"130, 100"},
{"folder":"Test2","number":"200"}
]}
you could use GroupBy to group by folder and String.Join() to concatenate numbers, like :
var result = Items
.GroupBy(x => x.folder)
.Select(x => new
{
folder = x.Key,
number = string.Join(",", x.Select(y => y.number).Where(z => !string.IsNullOrEmpty(z)))
}).ToList();
Test in dotnetfiddle : https://dotnetfiddle.net/FDvSmc

Remove From Duplicate Starting Names From List Linq

I have a list of paths that look like
//servername/d$/directory
I am getting the serverName from the path with the following
var host = somePath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
I want to refine this list to only 1 server Name listed (say the first one found)
Example
if the list contains
//serverA/d$/directoryA
//serverA/d$/directoryB
//serverA/d$/directoryC
//serverB/d$/directoryD
//serverB/d$/directoryE
the list would turn into
//serverA/d$/directoryA
//serverB/d$/directoryD
You can group them by the server name (by trimming the start and splitting on the / character and taking the first item), and then select the first item from each group into a new list:
var serverNames = new List<string>
{
"//serverA/d$/directoryA",
"//serverA/d$/directoryB",
"//serverA/d$/directoryC",
"//serverB/d$/directoryD",
"//serverB/d$/directoryE",
};
var results = serverNames
.GroupBy(name => name.TrimStart('/').Split('/')[0])
.Select(group => group.First())
.ToList();
From your first code example it's not clear if the paths begin with \, so to handle both cases you can do:
var results = serverNames
.GroupBy(name => name.TrimStart('\\', '/', ' ').Split('\\', '/')[0])
.Select(group => group.First())
.ToList();

Difficulty with LINQ Query writing custom sort logic

I have files like Avinash_Create.sql, Avinash_Insert.sql, Avinash_Update.sql , Avinash_Delete.sql.
I need to iterate over the files list and group them based on the name and order by create, insert, update, and delete files.
I am finding it difficult difficult to accomplish. This is what I have so far:
var userGroups = shortfilenames.GroupBy(s => s.Substring(0, s.IndexOf('_')))
.Select(g => g.OrderBy(x => x.Substring(x.IndexOf('_')).Contains("CREATE"))
.ThenBy(x => x.Substring(x.IndexOf('_')).Contains("INSERT"))
.ThenBy(x => x.Substring(x.IndexOf('_')).Contains("UPDATE"))
.ThenBy(x => x.Substring(x.IndexOf('_')).Contains("DELETE")));
The above query is grouping by name 'Avinash' but not working for custom ordering. Please help.
Update:
Please see updated query , still it is not sorting properly
Uses Split to extract the relevant sections of the string. Converts the result to upper case, which seems to be missing from your attempt. Additionally makes it a bit shorter by using an array to hold your custom sort order and then Array.IndexOf to get a sort order from it, rather than multiple OrderBy/ThenBy.
var ordering = new [] {"CREATE", "INSERT", "UPDATE", "DELETE"};
var results = shortfilenames.GroupBy(s => s.Split('_')[0])
.Select(g => g.OrderBy(x => Array.IndexOf(ordering, x.Split('_')[1].Split('.')[0].ToUpper())));
This seems to be what what you want:
var shortfilenames = new List<string>(){"Avinash_Create.sql" , "Avinash_Insert.sql" , "Avinash_Update.sql" , "Avinash_Delete.sql"};
var userGroups = shortfilenames
.Select(fn =>
{
string fileName = Path.GetFileNameWithoutExtension(fn);
string[] nameAndAction = fileName.Split('_');
return new
{
extension = Path.GetExtension(fn),
fileName,
name = nameAndAction[0],
action = nameAndAction[1]
};
})
.GroupBy(x => x.name)
.Select(g => g.OrderByDescending(x => x.action.Equals("CREATE", StringComparison.InvariantCultureIgnoreCase))
.ThenByDescending(x => x.action.Equals("INSERT", StringComparison.InvariantCultureIgnoreCase))
.ThenByDescending(x => x.action.Equals("UPDATE", StringComparison.InvariantCultureIgnoreCase))
.ThenByDescending(x => x.action.Equals("DELETE", StringComparison.InvariantCultureIgnoreCase))
.ToList());
foreach (var ug in userGroups)
foreach (var x in ug)
Console.WriteLine("{0} {1}", x.name, x.action);
prints out:
Avinash Create
Avinash Insert
Avinash Update
Avinash Delete
Presumes that the file-names always contain the underscore.

How to ignore blank lines with linq when importing from CSV.

Since I have just started linq, the question may be considered noob
I have a scenario where I have to import a remote csv and update it in database.
Previously I was using traditional approach i.e reading line by line splitting and the updating.
The query that I have written is as follows
var WItems =
( from ln in File.ReadAllLines(FilePath).Skip(1)
let columns = ln.Split(',')
select new
{
Style = Convert.ToString(columns[0].Trim()),
UPC = Convert.ToString(columns[1].Trim()),
Description = Convert.ToString(columns[2].Trim()),
FabricContent = Convert.ToString(columns[3].Trim()),
CareInstruction = Convert.ToString(columns[4].Trim()),
Color = Convert.ToString(columns[5]),
Size = Convert.ToString(columns[6].Trim()),
Price = Convert.ToString(columns[7].Trim()),
Category = Convert.ToString(columns[8].Trim()),
SubCategory = Convert.ToString(columns[9].Trim()),
Stock = Convert.ToString(columns[10].Trim()),
} ).ToList();
This query works well when there are no blank lines at the bottom, but throws error if there are blank lines at the bottom. My question is how can i split only those lines Which has something written or which is not blank.
Add Where clause to your query:
from ln in File.ReadAllLines(FilePath)
.Skip(1)
.Where(s => !string.IsNullOrWhiteSpace(s))
// further code...
Add non emptiness check:
var WItems = (from ln in File.ReadAllLines(FilePath)
.Skip(1)
.Where(item => !String.IsNullOrWhiteSpace(item))
let columns = ln.Split(',')
select new { ... }).ToList()
Alternative - check if columns really contains 11 items:
File.ReadAllLines(FilePath).Skip(1)
.Select(item => item.Split(','))
.Where(cols => cols.Count() == 11).Select(columns => new { ... })

Categories