How to deal with parallel arrays in LINQ? - c#

I have 2 separate arrays (coming from Json, but that's not important). They are lined up... i.e. arr1[1] goes with arr2[1].
I want to create a list of Test objects with a few catches:
1) both arr1 and arr2 value can't be null
2) I'm only interested in indexes where the arr1 element is a multiple of 5
This is what I have so far:
class Test
{
public double d1;
public double d2;
}
class Program
{
static void Main(string[] args)
{
string[] arr1 = new string[] { "0", "2", "5", "7", "10", "11", null, "13", "15" };
string[] arr2 = new string[] { "11", "13", "56", "8", null, "44", "55", "66", "77" };
var v = arr1.Where(x => !String.IsNullOrEmpty(x)).Select(x => Double.Parse(x)).Where(x => (x % 5) == 0).Select((x, y) => new Test
{
d1 = x,
d2 = Double.Parse(arr2[y])
});
}
}
I'm not sure how to skip the ones where arr2 is null though and the alignment is getting messed up.

In order not to mess up alignment, you should first .Zip the two arrays. Then, if I understand correctly, those indices that have null as value in either array should be skipped, so you filter those out with .Where, then do the rest of your logic.
class Test
{
public double d1;
public double d2;
}
class Program
{
static void Main(string[] args)
{
string[] arr1 = new string[] { "0", "2", "5", "7", "10", "11", null, "13", "15" };
string[] arr2 = new string[] { "11", "13", "56", "8", null, "44", "55", "66", "77" };
var v = arr1
.Zip(arr2, (x, y) => new {x, y})
.Where(a => !string.IsNullOrEmpty(a.x) && !string.IsNullOrEmpty(a.y))
.Select(a => new Test { d1 = double.Parse(a.x), d2 = double.Parse(a.y) })
.Where(a => (a.d1 % 5) == 0);
// TODO, ready to enumerate over v.
}
}

You can filter by where condition as below.
class Program
{
static void Main(string[] args)
{
string[] arr1 = new string[] { "0", "2", "5", "7", "10", "11", null, "13", "15" };
string[] arr2 = new string[] { "11", "13", "56", "8", null, "44", "55", "66", "77" };
var v = arr1
.Zip(arr2, (x, y) => new { x, y })
.Where(a => !string.IsNullOrEmpty(a.x) && !string.IsNullOrEmpty(a.y))
.Select(a => new Test { d1 = double.Parse(a.x), d2 = double.Parse(a.y) })
.Where(a => (a.d1 % 5) == 0);
}
}

Related

How to out all the int values from a string array and store that int values in another array

There are words and int values in a string array. My goal is to retrieve the int values from another array. I have seen two methods for converting and finding int values from a string array.
To get all the int values from the string, I first create another int array and use an Array.ConvertAll init. The second method is to loop through isDigit().
Now, the problem is that I cannot find a way to store that value in an int array that has been converted to an int. The final goal is to find the minimum and maximum value from the converted values.
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int result;
int[] num = Array.ConvertAll(strArray1, x =>
{
bool convertStrIntoInt = int.TryParse(x, out int result);
return result;
});
In here, I don't how to get the result outside of it to do a sort to find min and max values.
I don't understand what you want but if you want only int then use this
List<int> list = new List<int>();
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
foreach (string str in strArray1)
{
if (int.TryParse(str, out int val))
{
list.Add(val);
}
}
int[] vs = list.ToArray();
now all the int values are stored in vs array, if there are some words which contains the int value and you want them to be extracted you can use regex to find the digits in word also
I'd use LINQ for this:
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int[] num =
(
from x in strArray1
let n = int.TryParse(x, out int n) ? (int?)n : null
where n.HasValue
select n.Value
).ToArray();
That outputs:
Then you can do this:
int max = num.Max();
int min = num.Min();
Little optimized solution could be something like below
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
var numArray = strArray1.Where(var=> new Regex(#"^\d+").IsMatch(var)).ToArray();
var res = Array.ConvertAll(numArray,s => int.Parse(s));
If we don't want to use Regex can try something like below
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int testNum;
var numArray = strArray1.Where(var=> int.TryParse(var,out testNum)).ToArray();
var res = Array.ConvertAll(numArray,s => int.Parse(s));
You can then get max and min value using
res.Min(), res.Max()
This should give you a starting point for your problem
You can try Regex like below :
string[] strArray1 = {"Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109"};
int[] num = strArray1.Where(v => Regex.IsMatch(v, #"^\d+$")).Select(int.Parse).ToArray();
int min = num.Min();
int max = num.Max();
As you don't want to use Regex, you can go with your solution, just do a small modification to get your desired result. Try this :
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int[] num = Array.ConvertAll(strArray1, x =>
{
bool convertStrIntoInt = int.TryParse(x, out int result);
return result;
}).Where(x => x > 0).ToArray();
int max = num.OrderByDescending(c => c).ToArray()[0];
int min = num.OrderBy(c => c).ToArray()[0];
Here is another way to get int values from a string array into an int array.
Try it on dotnetfiddle.
public static class Extensions
{
public static int[] ToIntegerArray(this string[] sender)
{
var intArray = Array
.ConvertAll(sender,
(input) => new {
IsInteger = int.TryParse(input, out var integerValue),
Value = integerValue
})
.Where(result => result.IsInteger)
.Select(result => result.Value)
.ToArray();
return intArray;
}
}
Use
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
int[] intArray = strArray1.ToIntegerArray();
Array.Sort(intArray);
foreach (var value in intArray)
{
Console.WriteLine(value);
}
Console.WriteLine($"Min: {intArray.Min()}");
Console.WriteLine($"Max: {intArray.Max()}");
Targeting your intial question:
I don't [know] how to get the result outside of it to do a sort to find min and max values.
You simply can't get a complete solution for your Problem using ConvertAll() with a "normal" int.
So if we take a look at your result:
int[] num = Array.ConvertAll(strArray1, x =>
{
bool convertStrIntoInt = int.TryParse(x, out int result);
return result;
});
// num: int[8] { 0, 99, 0, 3, 0, 12, 0, 109 }
We can see each word will result in a 0, since 0 will be returned if the parsing failed - see: Int32.TryParse(...).
And therefore it is impossible to differentiate between an real 0 in your input or a word, which could not be parsed.
But we can tweek the convert a little bit by using Nullable<int>/int?
int?[] num = Array.ConvertAll(strArray1, x =>
{
return (int?)( int.TryParse(x, out int result) ? result : null);
});
// num: Nullable<int>[8] { null, 99, null, 3, null, 12, null, 109 }
So with this we are able to differ between a 0 and a word - represented by null.
Now you can perform other operations like num.Max() and num.Min().
If you need an int[] array, you have add some more function calls.
int[] num = Array.ConvertAll(strArray1, x =>
{
return (int?)( int.TryParse(x, out int result) ? result : null);
}).OfType<int>().ToArray();
//num: int[4] { 99, 3, 12, 109 }
So this is not quite optimal.
My solution for this would be a simple loop.
// Your intput
string[] strArray1 = { "Bautik", "99", "Sagar", "3", "Tisha", "12", "Riya", "109" };
// Output Variables
List<int> result = new();
int min = int.MaxValue;
int max = int.MinValue;
// Loop
foreach( string item in strArray1)
{
if(int.TryParse(item, out int value))
{
result.Add(value);
min = min > value ? value : min;
max = max < value ? value : max;
}
}
// Output
// result: List<int>[4] { 99, 3, 12, 109 }
// min: 3
// max: 109
As already mentioned by Gian Paolo in the comments of this answer
working with a List<int> is much easier than working with an int[]
..., but if you really need an array, then you can just call ToArray().
int[] resultArray = result.ToArray();
Which results in int[4] { 99, 3, 12, 109 }.

How to save the entire contents of datagridview into the word document using office.word.interop.dll instead of spire.doc.dll?

How to implement the logic of the 1st block of code using Microsoft.Office.Interop.Word.dll?
Now I am using third party dll(Spire.Doc.dll), instead of Spire.Doc.dll. I want to use Microsoft.Office.Interop.Word.dll.
Please help me to implement this logic using the office word dll. Thanks
And in the 2nd block of codei tried to implement the logic og 1st block of code , i ahve achieved upto some extent however i coud not implement the complent logic of 1st block of code. it does not go well with the actual need. on button click event of more than once ( several times) all exported datagridview into word document are overlapping with each other so how to avoid the overlapping and save all tables properly(table right below the table)? please guide me to implement the above code logic.
All exported Datagridview content is getting merged in a single place (getting merged with each other) is there a way to save them in a well-organized way (recently exported table below the previously exported table)?
How to avoid overlapping? on button click event of more than once ( several times) all exported datagridview into word document are overlapping with each other so how to avoid the overlapping and save all tables properly(table right below the table)?
// 1st block of code (using Spire.Doc.dll)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Spire.Doc;
using Spire.Doc.Documents;
using Spire.License;
using Spire.Doc.Fields;
namespace Export_Datagridview
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string filename;
public string Reportfile_path;
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add("1");
dt.Columns.Add("2");
dt.Columns.Add("3");
dt.Columns.Add("4");
dt.Columns.Add("5");
dt.Columns.Add("6");
dt.Columns.Add("7");
dt.Columns.Add("8");
dt.Columns.Add("9");
dt.Columns.Add("10");
dt.Columns.Add("11");
dt.Columns.Add("12");
dt.Columns.Add("13");
dt.Columns.Add("14");
dt.Columns.Add("15");
dt.Columns.Add("16");
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13", 14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13", 14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dataGridView1.DataSource = dt;
}
private void button1_Click(object sender, EventArgs e)
{
export_datagridview();
}
private void export_datagridview()
{
string time = DateTime.Now.ToString("HH:mm:ss");
string date = DateTime.Today.ToShortDateString();
filename = Reportfile_path + "sample" + ".doc";
Document document = new Document();
try
{
document.LoadFromFile(filename, FileFormat.Doc);
}
catch
{
}
int xx = 0, yy = 0, section_number = 0;
Section section = new Section(document);
Paragraph paragraph = section.AddParagraph();
paragraph = section.Paragraphs.Count > 0 ? section.Paragraphs[0] : section.AddParagraph();
yy = document.Sections.Count;
if (yy == 0)
{
section_number = yy;
section = document.AddSection();
section = document.Sections[section_number];
}
else
{
section_number = yy - 1;
section = document.Sections[section_number];
}
xx = section.Tables.Count;
if (xx == 5)
{
section_number++;
section = document.AddSection();
section = document.Sections[section_number];
}
else
{
section = document.Sections[section_number];
}
paragraph = section.AddParagraph();
paragraph.AppendText("\t\t SOMETHING");
paragraph = section.AddParagraph();
paragraph = section.AddParagraph();
paragraph.AppendText("Something\t\t:\tsomething");
paragraph = section.AddParagraph();
paragraph.AppendText("something\t\t:\tsomething");
Add_Table(dataGridView1, filename, section);
document.SaveToFile(filename, FileFormat.Doc);
}
private void Add_Table(DataGridView dGV, string filename, Section section)
{
Spire.Doc.Table table = section.AddTable();
table.ResetCells(dGV.RowCount, dGV.ColumnCount);
table.ResetCells(dGV.RowCount + 1, dGV.ColumnCount);
// first row
TableRow row = table.Rows[0];
row.IsHeader = true;
row.Height = 22;
row.HeightType = TableRowHeightType.Exactly;
row.RowFormat.BackColor = Color.Gray;
for (int i = 0; i < dGV.ColumnCount; i++)
{
row.Cells[i].CellFormat.VerticalAlignment = VerticalAlignment.Middle;
Paragraph p = row.Cells[i].AddParagraph();
p.Format.HorizontalAlignment = Spire.Doc.Documents.HorizontalAlignment.Center;
TextRange txtRange = p.AppendText(Convert.ToString(dGV.Columns[i].HeaderText));
txtRange.CharacterFormat.Bold = true;
}
for (int r = 0; r < dGV.RowCount; r++)
{
TableRow dataRow = table.Rows[r + 1];
dataRow.Height = 22;
dataRow.HeightType = TableRowHeightType.Exactly;
dataRow.RowFormat.BackColor = Color.Empty;
for (int c = 0; c < dGV.ColumnCount; c++)
{
dataRow.Cells[c].CellFormat.VerticalAlignment = VerticalAlignment.Middle;
row.Cells[c].Width = 80;
dataRow.Cells[c].Width = 80;
dataRow.Cells[c].AddParagraph().AppendText(Convert.ToString(dGV.Rows[r].Cells[c].Value));
}
}
}
}
}
// 2nd block of code (using Microsoft.Office.Interop.Word.dll)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace Save_DataGridView_As_Word_Doc
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public string filename;
public string filepath;
private void Form1_Load(object sender, EventArgs e)
{
DataTable dt = new DataTable();
dt.Columns.Add("1");
dt.Columns.Add("2");
dt.Columns.Add("3");
dt.Columns.Add("4");
dt.Columns.Add("5");
dt.Columns.Add("6");
dt.Columns.Add("7");
dt.Columns.Add("8");
dt.Columns.Add("9");
dt.Columns.Add("10");
dt.Columns.Add("11");
dt.Columns.Add("12");
dt.Columns.Add("13");
dt.Columns.Add("14");
dt.Columns.Add("15");
dt.Columns.Add("16");
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dt.Rows.Add(new object[] { "1", 2, "3", "4", "5", 6, "7", "8", "9", 10, "11", "12", "13",
14, "15", "16" });
dataGridView1.DataSource = dt;
}
private void button1_Click(object sender, EventArgs e)
{
save_datagridview(dataGridView1, filename);
}
public void save_datagridview(DataGridView DGV, string filename)
{
string time = DateTime.Now.ToString("HH:mm:ss");
string date = DateTime.Today.ToShortDateString();
filename = filepath + #"D:\datagridview" + ".docx";
var application = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document doc = new Microsoft.Office.Interop.Word.Document();
try
{
var originalDocument = application.Documents.Open(filename);
}
catch
{
}
if (DGV.Rows.Count != 0)
{
int RowCount = DGV.Rows.Count;
int ColumnCount = DGV.Columns.Count;
Object[,] DataArray = new object[RowCount + 1, ColumnCount + 1];
int r = 0; for (int c = 0; c <= ColumnCount - 1; c++)
{
for (r = 0; r <= RowCount - 1; r++)
{
DataArray[r, c] = DGV.Rows[r].Cells[c].Value;
}
}
application.ActiveDocument.PageSetup.Orientation =
Microsoft.Office.Interop.Word.WdOrientation.wdOrientLandscape;
dynamic orange = application.ActiveDocument.Content.Application.Selection.Range;
string otemp = "";
for (r = 0; r <= RowCount - 1; r++)
{
for (int c = 0; c <= ColumnCount - 1; c++)
{
otemp = otemp + DataArray[r, c] + "\t";
}
}
orange.Text = otemp;
object Separator = Microsoft.Office.Interop.Word.WdTableFieldSeparator.wdSeparateByTabs;
object ApplyBorders = true;
object AutoFit = true;
object AutoFitBehavior =
Microsoft.Office.Interop.Word.WdAutoFitBehavior.wdAutoFitContent;
orange.ConvertToTable(ref Separator, ref RowCount, ref ColumnCount, Type.Missing,
Type.Missing, ref ApplyBorders, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, ref AutoFit, ref AutoFitBehavior, Type.Missing);
orange.Select();
application.ActiveDocument.Application.Selection.Tables[1].Select();
application.ActiveDocument.Application.Selection.Tables[1].Rows.AllowBreakAcrossPages = 0;
application.ActiveDocument.Application.Selection.Tables[1].Rows.Alignment = 0;
application.ActiveDocument.Application.Selection.Tables[1].Rows[1].Select();
application.ActiveDocument.Application.Selection.InsertRowsAbove(1);
application.ActiveDocument.Application.Selection.Tables[1].Rows[1].Select();
application.ActiveDocument.Application.Selection.Tables[1].Rows[1].Range.Bold = 1;
application.ActiveDocument.Application.Selection.Tables[1].Range.Font.Name =
"Tahoma";
application.ActiveDocument.Application.Selection.Tables[1].Rows[1].Range.Font.Size =
14;
for (int c = 0; c <= ColumnCount - 1; c++)
{
application.ActiveDocument.Application.Selection.Tables[1].Cell(1, c + 1).Range.Text
= dataGridView1.Columns[c].HeaderText;
}
application.ActiveDocument.Application.Selection.Tables[1].set_Style("Grid Table 4 -
Accent 5");
application.ActiveDocument.Application.Selection.Tables[1].Rows[1].Select();
application.ActiveDocument.Application.Selection.Cells.VerticalAlignment =
Microsoft.Office.Interop.Word.WdCellVerticalAlignment.wdCellAlignVerticalCenter;
foreach (Microsoft.Office.Interop.Word.Section section in
application.ActiveDocument.Application.ActiveDocument.Sections)
{
Microsoft.Office.Interop.Word.Range headerRange =
section.Headers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
headerRange.Fields.Add(headerRange,
Microsoft.Office.Interop.Word.WdFieldType.wdFieldPage);
headerRange.Text = "XYZ";
headerRange.Font.Size = 18;
headerRange.ParagraphFormat.Alignment =
Microsoft.Office.Interop.Word.WdParagraphAlignment.wdAlignParagraphCenter;
}
//object start = 0, end = 0;
//Microsoft.Office.Interop.Word.Range rng1 = application.ActiveDocument.Range(ref start,
ref end);
//Microsoft.Office.Interop.Word.Range rng2 = application.ActiveDocument.Range(ref start,
ref end);
//rng1.SetRange(rng1.End, rng1.End);
//rng1.Text = "\t\t\t\t\t\t xyz\t :\t xyz ";
//rng2.SetRange(rng2.End, rng2.End);
//rng2.Text = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t zyz\t :\t xyz ";
application.ActiveDocument.Save();
application.Quit();
MessageBox.Show("Document created successfully !");
}
}
}
}
Before I start, it should be noted, as others have commented in the other questions you have posted, is that using “interop” is somewhat discouraged since there are other “free” third-party libraries that work just as well if not better. Example, interop is notoriously slow when dealing with large documents. However, I am also aware that in some cases you may not have an option. With that said, below is an example of adding tables to a Word document using interop.
In the current posted code, it is difficult to tell if you want to add the tables to a “new” document or add the tables to an existing document. The code below adds the tables to a “new” Word document.
Also, I recommend you break up the code to do certain things as this will make it easier to maintain and make changes. Example, having a method that simply “adds” the data from the grid to the table, without formatting the table. Then another method that formats the table and possibly another method to format the Word document. Mixing these things together in one method makes it difficult to maintain and make changes.
Given this, it would appear that a particular method could come in handy. This method would take two parameters… A DataGridView and a “Word Document.” This method would take the data from the given DataGridView and add the data to a new table and place that table to the end of the given Word Document.
As you may be aware of, dealing with ranges in Word can be cumbersome and placing the table in a particular paragraph will require extra work, however, it is doable. Because of this, the code below simply adds the table to the end of the document.
This method “Add_DGV_To_Doc” may look something like below. Following the code below, it first gets the range that is the end of the document… Word.Range range = doc.Bookmarks.get_Item(ref endOfDoc).Range; … a new paragraph will be added and the table will be placed in that new paragraph.
When creating the table to add to the Word document, an extra row is added for the header text. Then a new paragraph is added to the Word document. First a loop is started to set the header text for each column. Then the rows from the grid are added to the table. Lastly FormatTable() is called to format the new table. It appears your current posted code is doing unnecessary work by creating a string array then a string? All this appears unnecessary when you can simply read the data directly from the DataGridView.
private void Add_DGV_To_Doc(DataGridView dgv, Word.Document doc) {
object mis = System.Reflection.Missing.Value;
object endOfDoc = "\\endofdoc";
Word.Range range = doc.Bookmarks.get_Item(ref endOfDoc).Range;
Word.Table table = doc.Tables.Add(range, dgv.RowCount + 1, dgv.ColumnCount, ref mis, ref mis);
object prarRange = doc.Bookmarks.get_Item(ref endOfDoc).Range;
Word.Paragraph para = doc.Content.Paragraphs.Add(ref prarRange);
para.Range.Text = Environment.NewLine;
string value;
for (int col = 0; col < dgv.ColumnCount; col++) {
table.Cell(1, col + 1).Range.Text = dgv.Columns[col].HeaderText;
}
int tableRow = 2;
for (int row = 0; row < dgv.RowCount; row++) {
if (!dgv.Rows[row].IsNewRow) {
for (int col = 0; col < dgv.ColumnCount; col++) {
value = "";
if (dgv.Rows[row].Cells[col].Value != null) {
value = dgv.Rows[row].Cells[col].Value.ToString();
}
table.Cell(tableRow, col + 1).Range.Text = value;
}
tableRow++;
}
}
FormatTable(table);
}
Next is a method that formats the table.
private void FormatTable(Word.Table table) {
table.Rows[1].Range.Bold = 1;
table.Range.Font.Name = "Tahoma";
table.Rows[1].Range.Font.Size = 14;
table.set_Style("Grid Table 4 - Accent 5");
table.Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
}
Next is a method to format the Word document.
private void SetHeadersForSections(Word.Document doc) {
foreach (Word.Section section in doc.Sections) {
Word.Range headerRange = section.Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
headerRange.Fields.Add(headerRange, Word.WdFieldType.wdFieldPage);
headerRange.Text = "XYZ";
headerRange.Font.Size = 18;
headerRange.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
}
}
Also, in your current posted code, it is unwise to ignore exceptions as the following code does…
try
{
var originalDocument = application.Documents.Open(filename);
}
catch
{
}
Having an “empty” catch is basically ignoring the error and continuing. Minimum you should display “what” the error is and/or deal with the error before continuing. This is frowned upon in just about any environment, and will get negative marks in an academic environment.
Lastly, it should be noted that when you use “com” objects such as a “Word Application” and a “Word Document” … it is YOUR responsibility to “release” the com objects your code creates. Your code does not do this, therefore, if you run the code numerous times, you will probably see numerous “Microsoft Word” processes still running even after you quit the program.
Therefore, your code should release these “com” objects before the code exits to avoid this resource leak. This can be seen in the “finally” code section of the try/catch/finally block below.
Putting all this together, the code below adds two (2) different grids to a Word document, and saves the Word document when button1 is clicked. The first dataGridView1 is filled with sixteen (16) rows and columns. The second datagridview2 is filled with ten (10) rows and columns.
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
DataTable dt = GetTable(16, 16);
dataGridView1.DataSource = dt;
dt = GetTable(10, 10);
dataGridView2.DataSource = dt;
}
private DataTable GetTable(int totCol, int totRow) {
DataTable dt = new DataTable();
for (int i = 0; i < totCol; i++) {
dt.Columns.Add("H " + (i + 1).ToString());
}
for (int i = 0; i < totRow; i++) {
dt.Rows.Add(GetRowArray(totCol));
}
return dt;
}
private object[] GetRowArray(int size) {
object[] obj = new object[size];
for (int i = 0; i < size; i++) {
obj[i] = (i + 1).ToString();
}
return obj;
}
private void button1_Click(object sender, EventArgs e) {
save_datagridview(dataGridView1);
}
public void save_datagridview(DataGridView DGV) {
string filename = #"D:\Test\datagridview.docx";
Word.Application app = null;
Word.Document doc = null;
try {
app = new Word.Application();
//app.Visible = true;
doc = app.Documents.Add();
doc.PageSetup.Orientation = Word.WdOrientation.wdOrientLandscape;
Add_DGV_To_Doc(dataGridView1, doc);
Add_DGV_To_Doc(dataGridView2, doc);
SetHeadersForSections(doc);
doc.SaveAs2(filename);
MessageBox.Show("Document created successfully !");
}
catch (Exception e) {
MessageBox.Show("ERROR: " + e.Message);
}
finally {
if (doc != null) {
Marshal.ReleaseComObject(doc);
}
if (app != null) {
app.Quit();
Marshal.ReleaseComObject(app);
}
}
}
Hope this helps.

Can i get unmatched values from two texbox like this way?

I can get values which are already matched. But i can't get unmatched values. How to make it work. Give me some advice guys
private void button13_Click(object sender, EventArgs e)
{
String a = textBox3.Text;
String b = textBox4.Text;
string test = "";
string[] titles1 = a.Split(new[] { ';', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
string[] titles2 = b.Split(new[] { ';', '\t', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
var duplicates = titles1.Distinct().Concat(titles2.Distinct()).GroupBy(title => title).Where(possibleDuplicates => possibleDuplicates.Skip(1).Any()).Select(duplicate => duplicate.First());
int i = 0;
foreach (string duplicate in duplicates)
{
//test = test + duplicate + "\r\n";
System.Data.DataTable table = new System.Data.DataTable();
table.Columns.Add("Missed call");
table.Rows.Add(duplicate);
Excel_read.DataSource = table;
}
}
This may help for you
var result = titles1.Except(titles2).Concat(titles2.Except(titles1)).ToArray();
To find the differences you may use the following code (it is written on the fly, I don't say it is an performance-optimized algorithm, it is just an idea how your problem may be solved):
var list1 = new List<int> {1, 2, 3, 5};
var list2 = new List<int> {1, 2, 4, 5, 6};
var differences = list1.Where(v => !list2.Contains(v)).Concat(
list2.Where(v => !list1.Contains(v)));
// Or this compact version:
// var differences = list1.Except(list2).Concat(list2.Except(list1));
The differences IEnumerable will will contain the following result:
{3, 4, 6}
This way:
List<string> list1 = new List<string> { "1", "2", "3", "4", "5", "7", "9"};
List<string> list2 = new List<string> { "1", "2", "3", "4", "5", "6", "8" };
List<string> list3 = list1;
list3.AddRange(list2);
list3 = list3.GroupBy(x => x).Where(x => x.Count() == 1).Select(x => x.Key).ToList();

How to calculate the sum of column score and time

I have a 2-dimensional array like below.
If I want to sum all time and score of rows of Each ID that start from lesson startpoint=E and ends by lesson endspoint=I. In the case below, for ID 1 it become (time=190+195+200=585 and score=3+3+4=10) and ID 3 that (time=190+210+160=560 and score=5+4+4=13).
I already came up with following loop.
ID Lesson Time Score
1 C 165 4
1 E 190 3
1 H 195 3
1 I 200 4
2 A 100 2
2 B 150 5
2 D 210 2
2 E 110 4
3 D 130 5
3 E 190 5
3 H 210 4
3 I 160 4
3 J 110 4
4 E 120 3
4 H 150 4
4 J 170 4
-
for (int i=0; i<SizeofDataGrid;i++)//save datatable into array
{
for (int j=0; j<4;j++)
{
FILTERED[i,j]=Convert.ToString(interaction.Rows[i][j]);
}
}
for (int i = 0; i < FILTERED.GetLength(0); i++)
{
string UNIQUEID = UniqueUserId[i];
for (int j = 0; j < SizeofDataGrid; j++)
{
if (UNIQUEID == FILTERED[j,0])// match ID
{
for (int x = 0; x < SizeofDataGrid; x++)
{
if (startpoint == FILTERED[j, 1]) //Match start Lesson
{
TotalTime[1, i] = TotalTime[1, i] + Convert.ToUInt16(FILTERED[j, 2]);
TotalTime[0, i] = i;
TotalScore[1, i] = TotalScore[1, i] + Convert.ToUInt16(FILTERED[j, 3]);
TotalScore[0, i] = i;
}
}
}
}
}
Try this:
// this method does the calculations then puts the values in the totalScore and totaltime variables
public void DoCalculations(string[,] data, string id, out int totalScore, out int totalTime)
{
totalTime = 0;
totalScore = 0;
for (int i = 0; i < data.GetLength(0); i++)
{
if (data[i, 0] != id) continue;
// modify this string to contain the lessons between E and I
if (!"EFGHI".Contains(data[i, 1])) continue;
// do proper error checking unless you're sure they'll always be integers
totalTime += int.Parse(data[i, 2]);
totalScore += int.Parse(data[i, 3]);
}
}
And this is the usage example:
string[,] data = new string[,]
{
{"1", "C", "165", "4"},
{"1", "E", "190", "3"},
{"1", "H", "195", "3"},
{"1", "I", "200", "4"},
{"2", "A", "100", "2"},
{"2", "B", "150", "5"},
{"2", "D", "210", "2"},
{"2", "E", "110", "4"},
{"3", "D", "130", "5"},
{"3", "E", "190", "5"},
{"3", "H", "210", "4"},
{"3", "I", "160", "4"},
{"3", "J", "110", "4"},
{"4", "E", "120", "3"},
{"4", "H", "150", "4"},
{"4", "J", "170", "4"}
};
// will store the total score
int totalScore = 0;
// will store the total time
int totalTime = 0;
// calling the function for the id=3
DoCalculations(data, "3", out totalScore, out totalTime);
Console.WriteLine(totalTime); // will output: 560
Console.WriteLine(totalScore); // will output: 13
Do you know about the break statement? You should be able to create a conditional statement that checks for your condition, then put break; at the bottom of it and you will exit the loop.
I would try to avoid using string[,] FILTERED to store your data. You really can easily create strong data types instead. However, if you must use it then I would convert to a strong data type and then do the calculations.
So, starting with the raw data:
string[,] FILTERED = new string[16, 4]
{
{ "1", "C", "165", "4" },
{ "1", "E", "190", "3" },
{ "1", "H", "195", "3" },
{ "1", "I", "200", "4" },
{ "2", "A", "100", "2" },
{ "2", "B", "150", "5" },
{ "2", "D", "210", "2" },
{ "2", "E", "110", "4" },
{ "3", "D", "130", "5" },
{ "3", "E", "190", "5" },
{ "3", "H", "210", "4" },
{ "3", "I", "160", "4" },
{ "3", "J", "110", "4" },
{ "4", "E", "120", "3" },
{ "4", "H", "150", "4" },
{ "4", "J", "170", "4" },
};
I would first turn this into strongly-type data:
var data =
FILTERED
.Cast<string>()
.Select((x, n) => new { x, n })
.GroupBy(xn => xn.n / 4, xn => xn.x)
.Select(xs => new
{
ID = int.Parse(xs.ElementAt(0)),
Lession = xs.ElementAt(1),
Time = int.Parse(xs.ElementAt(2)),
Score = int.Parse(xs.ElementAt(3)),
});
This gives:
I would then do this query:
var result =
data
.GroupBy(x => x.ID)
.Select(xs => new
{
ID = xs.Key,
Lessions = xs
.Where(x => x.Lession.Intersect("EFGHI").Any())
.ToArray(),
})
.Select(x => new
{
x.ID,
Time = x.Lessions.Sum(y => y.Time),
Score = x.Lessions.Sum(y => y.Score),
})
.ToArray();
That gives me this result:
Now, just as an alternative to mucking around with the intermediate FILTERED array you could just get the data directly from the DataTable like this:
var data =
from row in interaction.Rows.Cast<DataRow>()
select new
{
ID = row.Field<int>(0),
Lession = row.Field<string>(1),
Time = row.Field<int>(2),
Score = row.Field<int>(3),
};

c# reversing and serializing a dictionary using linq

Was wondering is it possible to reverse a dictionary in a single LINQ statement?
The structure is as follows;
Dictionary<string, List<string>> original = new Dictionary<string, List<string>>()
{
{"s", new List<string>() { "1", "2", "3" }},
{"m", new List<string>() { "4", "5", "6" }},
{"l", new List<string>() { "7", "8", "9" }},
{"xl", new List<string>() { "10", "11", "12" }},
};
which i would like to convert to a dictionary of type;
Dictionary<string, string> Reverse = new Dictionary<string, string>()
{
{"1", "s"},
{"2", "s"}, //and so on
};
If you do:
var reversed = original.SelectMany(x => x.Value.Select(y => new KeyValuePair<string, string>(y, x.Key)));
then you get:
1 - s
2 - s
3 - s
4 - m
5 - m
etc.
Something like:
var result = (from kvp in original
from value in kvp.Value
select new {Key = value, Value = kvp.Key}).ToDictionary(a => a.Key, a => a.Value);
Or, if you prefer the method syntax:
var result = original.SelectMany(kvp => kvp.Value.Select(v => new {Key = v, Value = kvp.Key}))
.ToDictionary(a => a.Key, a => a.Value);
you can use a SelectMany to split the value sublists, and then reverse the Keys & Values into a new Dictionary using ToDictionary
var result = original
.SelectMany(k=> k.Value.Select(v => new { Key = v, Value = k.Key } ))
.ToDictionary( t=> t.Key, t=> t.Value);
For that you can use the SelectMany LINQ extension method:
var original = new Dictionary<string, List<string>>
{
{ "s", new List<string> { "1", "2", "3" } },
{ "m", new List<string> { "4", "5", "6" } },
{ "l", new List<string> { "7", "8", "9" } },
{ "xl", new List<string> { "10", "11", "12" } },
};
var keyValuePairs = original.SelectMany(o => o.Value.Select(v => new KeyValuePair<string, string>(v, o.Key)));

Categories

Resources