I have a task to generate a file , so this is the example of data(from excel)
A Enr
B Cds
C Cdr
D Der
A Enr
B Cds
What i want is when you already found the same data, for example : The first row is A Enr, and the fifth row is A Enr, if you already loop the first row and find the same data (the fifth row) , i dont want when the variable int i = 4 , it will loop the A Enr again to search the same data ,because it already been search from i = 0 (which is the A ENR in the first row)
How to effective way to do the loop, because if you use the for statement, line 5 (A) will be looped back to check the same data, and that's the thing I don't want because on line 1 (A) has looped and found the same data in row 5.
Code Example
for (int i = 0; i < row; i++)
{
for(int k = 0 ; k < row ;k++)
{
if (fulldatadetail[i][0] == fulldatadetail[k][0])
{
if (!File.Exists(path))
{
using (StreamWriter sw = File.CreateText(path))
{
sw.WriteLine(fulldatadetail[i][0]);
}
}
else if (File.Exists(path))
{
using (StreamWriter sw = File.AppendText(path))
{
sw.WriteLine(fulldatadetail[i][0]);
}
}
}
}
}
P.S: sry for bad grammar, im trying to improve my english ..
it linq, group by, tuple does sound familiar to you, why don't try GroupBy?
// assume index is A,B,C,D
// assume value is Enr,Cds
var result = datas.GroupBy(x=> (x.index, x.value));
use foreach then print your key, your key in IGrouping<T> now is something like Tuple.
Item1 is index, Item2 is value.
foreach(var item in result.ToList())
{
something.Write(item.Key.Item1);
something.WriteLine(item.Key.Item2);
}
Try to declare an int/bool array with size according to your distinct elements (probably 22 as i see in this example),
Now, every row increase the cell corresponding to the latter that you see (e.g a[x-'A']++), also on every row do the inner loop only if the corresponding cell is 0.
So basicly just mark whenever you see a character so that the next time you see it you will know that you already saw one.
Provided you're trying to omit duplicate rows of data, and the only check you need is that the lines are completely equal (and not just based on the first character), this code may help you. It keeps track of every found value in a list and skips outputting it if it has already been output before.
string path = #"C:\Some\Text\File.txt";
List<string> outputValues = new List<string>
{
"A Enr",
"B Cds",
"C Cdr",
"D Der",
"A Enr",
"B Cds"
};
List<string> foundValues = new List<string>();
foreach (string outputValue in outputValues)
{
if (foundValues.Contains(outputValue))
continue; // Doesn't output this output value twice
foundValues.Add(outputValue);
using (StreamWriter sw = File.Exists(path) ? File.AppendText(path) : File.CreateText(path))
{
sw.WriteLine(outputValue);
}
}
Related
I have a text file that looks like this
Words Words
Words Words
Words Words
1 34.4e+1
2 34.3e+1
3 34.2e+1
4 34.1e+1.... // and so on
I need to get the string number and concert it to decimal/double and then send it to an array where I can the use the array outside of the for loop to get the average via Enumerable.Chunk
decimal[] raw = new decimal[] { };
decimal[] rawAvgList = new decimal[] { };
decimal RawAvg = 0m;
try
{
string bPath = aPath + "\\" + fileName.Name + "\\textfilename.txt";
string[] readText = File.ReadAllLines(bPath);
readText = readText.Skip(3).ToArray();
foreach (var line in readText)
{
raw = new decimal[] { Decimal.Parse(line.Substring(9).ToString(), style1) };
for (int i = 0; i < raw.Length; i++)
{
Console.WriteLine("{0} \t {1}", raw[i], i++);
}
}
rawAvgList = raw.Chunk(20).Select(chunk => chunk.Average()).ToArray();
RawAvg = rawAvgList.Average();
}
So for when I call the array outside of the loop it only grabs the last number in the text file. Am I calling the information wrong? I swear I have tried all the different way to call the numbers from the text file and I just keep running into errors. The error range from it not liking me using skip and substring at the same time or and enumerable error where it returned the error and not the number. Anything to help, Thanks!
You are assigning the variable raw to a new value on each loop iteration, wiping out any value that was stored previously. The end result is that after the loop terminates, it will only contain the value from the last line in the file as you are seeing.
You can declare raw as a List<decimal> instead, then within the loop, you would do
raw.Add(Decimal.Parse(line.Substring(9).ToString(), style1));
This way, once the loop finishes, you'll have all the numbers and not just the last one.
I know how to read through all lines of a file and replace a selected line when a certain sequence of characters is found. The issue that I'm having at the moment is that I'm stuck with a structure that has no unique string to search for except for the main class name. So for example I'd know that the name of the class is "List_of_boats" and the structure tells me that 11 lines underneath that line is the value "items=2;" which I need to change to a certain value, depending on the amount of items I want to insert there.
Is there a way to use the foreach function or something to do this? I have provided some code that I've already got so far but I'm kind of stuck now.
var lines = File.ReadAllLines(fileToMerge);
var linID = 0;
foreach (var line in lines) {
if (line.Contains("ace_arsenal_saved_loadouts")) {
var newlinID = linID + 11; //go from ace_arsenal_saved_loadouts to "items=x;" to change number of items.
}
linID = linID + 1;
}
Convert the enumerable to an array, and loop through it by index:
var lines = File.ReadAllLines(fileToMerge).ToArray();
for (var linID = 0; linID < lines.Length; linID++) {
var line = lines[linID];
if (line.Contains("ace_arsenal_saved_loadouts")) {
var newlinID = linID + 11; //go from ace_arsenal_saved_loadouts to "items=x;" to change number of items.
}
}
my error is on the very last line, saying my index is out of range. Not sure what the problem is. I would like to continue using a list of lists or lists. I am trying to read a line of a csv file and separate that line into groups if one of the words in that line repeats; for example:
"hey how are you hey whats up"
hey how are you would be in one group and then hey whats up would be in the other group.
string[] ReadDirectory = Directory.GetFiles("C:\\Users\\-------", "*.csv");
List<List<List<string>>> myList = new List<List<List<string>>>();
List<string> CSVlist = new List<string>();
foreach (string file in ReadDirectory)
{
using (StreamReader readFile = new StreamReader(file))
{
int groupIndex = 0;
string line = readFile.ReadLine();
string[] headers = line.Split(',');
Array.Reverse(headers);
CSVlist.Add(headers[headers.Length - 1]);
myList.Add(new List<List<string>>());
for (int i = 0; i < headers.Length; i++)
{
if (headers[i].Contains("repeats") && headers[i + 1].Contains("repeats"))
{
myList.Add(new List<List<string>>());
groupIndex++;
}
myList[0][groupIndex].Add(headers[i]);
}
}
}
the problem resides when i =headers.Length-1, then headers[i + 1] is out of bounds. try:
for (int i = 0; i < headers.Length; i++)
{
if (i<headers.Length-1)
{
if (headers[i].Contains("repeats") && headers[i + 1].Contains("repeats"))
{
myList.Add(new List<List<string>>());
groupIndex++;
}
myList[0][groupIndex].Add(headers[i]);
}
}
Looking at the code, I'm not sure it'll do what you want it too (eg. if headers contains the exact word 'repeats', but this may just be example code so I'll ignore that) - but I'll focus on the error reported.
The exact error you reported is caused by this line:
myList[0][groupIndex].Add(headers[i]);
When you first add a nested list to myList, you don't add a nested list to that first nested list - so when the if statement is false, it tries to add the header into myList[0][0] where the second index is out of range because there is no inner list at myList[0].
Changing
myList.Add(new List<List<string>>());
to something like
var innerGroupList = new List<string>();
var groupList = new List<List<string>>();
groupList.Add(innerGroupList);
myList.Add(groupList);
will resolve the issue, but you won't get your expected outcome from the example data as the word 'repeats' is not there, you would need to do something like save each word in a Hashset, and check each word against that. If it already exists in the dictionary, split it into another group.
Please help me split column's field values into multiple rows.
Table
ID Name Location DeptNo
1 Jack Florida 101,102,103
I'm looking for output like this
ID Name Location DeptNo
1 Jack FLorida 101
1 Jack FLorida 102
1 Jack FLorida 103
I've figured out the configuration in ssis using script component but not sure about my code
Please check
public class ScriptMain : UserComponent
{
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
int[] Edpt = Row.DeptNo.ToInt().Split(new int[] { ',' }, IntSplitOptions.None);
int i = 0;
while (i < DeptNo.Length)
{
Output0Buffer.AddRow();
Output0Buffer.ID = Row.ID;
Output0Buffer.Name = Row.Name;
Output0Buffer.Location = Row.Location;
Output0Buffer.DeptNo = DeptNo[i];
i++;
}
}
}
99% of the way there.
Given a source like
SELECT
1 AS ID
, 'Jack' AS Name
, 'Florida' AS Location
, '101,102,103' AS DeptNo;
Your Script task becomes Asynchronous as it will not be a 1:1 input to output buffer. I made 3 changes to your script.
The first was in the creation of edpt array. There might be a way to split the strings and convert the result directly to a nullable integer array but it didn't come to mind.
string[] Edpt = Row.DeptNo.Split(new char[] { ',' });
The second changes was your for loop. while (i < DeptNo.Length) is going to look at each character in the source DeptNo string. so you'd have something like 11 output buffers created (which would then fail when it attempts to put the comma into an integer (unless it treats it as a char data type and then uses the ascii value). At any rate, to heck with while loops unless you need them. The foreach helps eliminate the dreaded off by one mistakes. So, I enumerate through my collection (Edpt) and for each value I find, I assign it to a loop scoped variable called item
foreach (var item in Edpt)
The final change is to the assignment in my output buffer. Output0Buffer.DeptNo = DeptNo[i]; again would only be access a specific value in the original string (1, 0, 1, ,, 1, 0, 2, ,, etc). Instead, you want to operate on the splitted array like Output0Buffer.DeptNo = Edpt[i]; But, since we don't need to do any of that ordinal access, we just reference item.
Output0Buffer.DeptNo = Int32.Parse(item);
The final code looks like
public override void Input0_ProcessInputRow(Input0Buffer Row)
{
// Create an array of the department numbers as strings
string[] Edpt = Row.DeptNo.Split(new char[] { ',' });
// no longer needed
int i = 0;
// foreach avoids off by one errors
foreach (var item in Edpt)
{
Output0Buffer.AddRow();
Output0Buffer.ID = Row.ID;
Output0Buffer.Name = Row.Name;
Output0Buffer.Location = Row.Location;
// use the iterator directly
Output0Buffer.DeptNo = Int32.Parse(item);
}
}
The program helps users to parse a text file by grouping certain part of the text files into "sections" array.
So the question is "Are there any methods to find out the line numbers/position within the array?" The program utilizes a foreach loop to read the "sections" array.
May someone please advise on the codes? Thanks!
namespace Testing
{
class Program
{
static void Main(string[] args)
{
TextReader tr = new StreamReader(#"C:\Test\new.txt");
String SplitBy = "----------------------------------------";
// Skip 5 lines of the original text file
for(var i = 0; i < 5; i++)
{
tr.ReadLine();
}
// Read the reststring
String fullLog = tr.ReadToEnd();
String[] sections = fullLog.Split(new string[] { SplitBy }, StringSplitOptions.None);
//String[] lines = sections.Skip(5).ToArray();
int t = 0;
// Tried using foreach (String r in sections.skip(4)) but skips sections instead of the Text lines found within each sections
foreach (String r in sections)
{
Console.WriteLine("The times are : " + t);
// Is there a way to know or get the "r" line number?
Console.WriteLine(r);
Console.WriteLine("============================================================");
t++;
}
}
}
}
A foreach loop doesn't have a loop counter of any kind. You can keep your own counter:
int number = 1;
foreach (var element in collection) {
// Do something with element and number,
number++;
}
or, perhaps easier, make use of LINQ's Enumerable.Select that gives you the current index:
var numberedElements = collection.Select((element, index) => new { element, index });
with numberedElements being a collection of anonymous type instances with properties element and index. In the case a file you can do this:
var numberedLines = File.ReadLines(filename)
.Select((Line,Number) => new { Line, Number });
with the advantage that the whole thing is processed lazily, so it will only read the parts of the file into memory that you actually use.
As far as I know, there is not a way to know which line number you are at within the file. You'd either have to keep track of the lines yourself, or read the file again until you get to that line and count along the way.
Edit:
So you're trying to get the line number of a string inside the array after the master string's been split by the SplitBy?
If there's a specific delimiter in that sub string, you could split it again - although, this might not give you what you're looking for, except...
You're essentially back at square one.
What you could do is try splitting the section string by newline characters. This should spit it out into an array that corresponds with line numbers inside the string.
Yes, you can use a for loop instead of foreach. Also, if you know the file isn't going to be too large, you can read all of the lines into an array with:
string[] lines = File.ReadAllLines(#"C:\Test\new.txt");
Well, don't use a foreach, use a for loop
for( int i = 0; i < sections.Length; ++ )
{
string section = sections[i];
int lineNum = i + 1;
}
You can of course maintain a counter when using a foreach loop as well, but there is no reason to since you have the standard for loop at your disposal which is made for this sort of thing.
Of course, this won't necessarily give you the line number of the string in the text file unless you split on Environment.NewLine. You are splitting on a large number of '-' characters and I have no idea how your file is structured. You'll likely end up underestimating the line number because all of the '---' bits will be discarded.
Not as your code is written. You must track the line number for yourself. Problematic areas of your code:
You skip 5 lines at the beginning of your code, you must track this.
Using the Split method, you are potentially "removing" lines from the original collection of lines. You must find away to know how many splits you have made, because they are an original part of the line count.
Rather than taking the approach you have, I suggest doing the parsing and searching within a classic indexed for-loop that visits each line of the file. This probably means giving up conveniences like Split, and rather looking for markers in the file manually with e.g. IndexOf.
I've got a much simpler solution to the questions after reading through all the answers yesterday.
As the string had a newline after each line, it is possible to split the strings and convert it into a new array which then is possible to find out the line number according to the array position.
The Codes:
foreach (String r in sections)
{
Console.WriteLine("The times are : " + t);
IList<String> names = r.Split('\n').ToList<String>();
}