Import numbers from an Excel column using C# - c#

I have an Excel file with one column which is filled with numbers. I would like to be read the numbers from this column into an array in C#. How can I do that?

The easiest way is probably to use the Excel ODBC driver. This allows you to use OdbcConnection to read the worksheet into a DataTable. You can then iterate over the table's Rows collection, copying the values into a list or array.

You can use Excel Interop and do something along the lines of:
Excel.Range firstCell = excelWorksheet.get_Range("A1", Type.Missing);
Excel.Range lastCell = excelWorksheet.get_Range("A10", Type.Missing);
Excel.Range worksheetCells = excelWorksheet.get_Range(firstCell, lastCell);
var cellValues = worksheetCells.Value2;
You should get an array of objects (1-based index), and can cast the contents using (for instance) Convert.ToDouble().

SpreadsheetGear for .NET can do it. Below is some C# source. Note that the SpreadsheetGear API is similar to the Excel API, so the code below could be adapted to Excel.
using System;
using SpreadsheetGear;
namespace Program
{
class Program
{
static void Main(string[] args)
{
// Load a workbook from disk and get the first worksheet.
var workbook = SpreadsheetGear.Factory.GetWorkbook(#"C:\tmp\Numbers.xlsx");
// Allocate a list of doubles to store the number.
var numbers = new System.Collections.Generic.List<double>();
var worksheet = workbook.Worksheets[0];
// Assuming that column A is the column with the numbers...
var columnA = worksheet.Cells["A:A"];
var usedRange = worksheet.UsedRange;
// Limit the cells we look at to the used range of the sheet.
var numberCells = usedRange.Intersect(columnA);
// Get the numbers into the list.
foreach (IRange cell in numberCells)
{
object val = cell.Value;
if (val is double)
numbers.Add((double)val);
}
// Write the numbers to the console.
foreach (double number in numbers)
Console.WriteLine("number={0}", number);
}
}
}
You can download the free SpreadsheetGear trial here if you want to try it yourself.
Disclaimer: I own SpreadsheetGear LLC

Related

NPOI issue with FirstRowNum and LastRowNum returning -1 for a sheet that has rows

When trying to get the rows from an Excel sheet using NPOI, FirstRowNum and LastRowNum return -1.
IWorkbook workbook = null;
List<ImportedKPI> excelRows = new List<ImportedKPI>();
MemoryStream ms = new MemoryStream(array);
ISheet sheet = null;
workbook = WorkbookFactory.Create(ms);
sheet = workbook.GetSheet(mapping.Sheet);
//Do some stuff here and try to get rows
for (int i = sheet.FirstRowNum; i <= sheet.LastRowNum; i++)
//sheet.FirstRowNum = -1 && sheet.LastRowNum = -1
Another worthy mention is that when I save open the file and close it (with LibreOffice) it asks if I want to save and after that it works.
When comparing the byte arrays before/after save they are different.
Turns out not all excel parsers work for all types.
And since I get excels by email I had to do a chain of responsibility pattern based on NPOI and ExcelDataReader nugets.
This means that the when the excel comes I try to use a first class to parse it (ExcelDataReader first) and if it's not successful it moves on to NPOI and tries to parse it with that.
Seems like the better way when there are many sources.

C# Reorder columns of Excel worksheet

I have an Excel worksheet with some data. I also have a List of the column headers of the worksheet. The headers in the list are in a different order than the headers in the worksheet, and I need to reorder the Excel worksheet's columns to be the same order as the list.
List<string> dataset1Variables = new List<string>() { "Variable1", "Variable2", "Variable3", "Variable4" };
The headers of my Excel sheet may look like this:
Variable 3 | Variable 1 | Variable 4 | Variable 2
I have come across this code to shift columns but this is only for moving 1 column to a specific location. The list might be completely mixed up so I would need to shift many columns.
Excel.Range copyRange = xlWs.Range["C:C"];
Excel.Range insertRange = xlWs.Range["A:A"];
insertRange.Insert(Excel.XlInsertShiftDirection.xlShiftToRight,
copyRange.Cut());
What would be the best approach for doing this? Preferably using Interop.
If you have an empty row right above your worksheet with data, you can add matching formula right above headers. In below assuming your list is on Sheet2 range B2:B5 and your data headers start on Sheet1 range A2:D2
Excel.Workbook myBook = xlApp.Workbooks.Open(#"path\excel.xlsx");
Excel.Worksheet ws = myBook.Worksheets[1];
// You can use all dynamic ranges instead
// Excel.Range xlRng = ws.Range[ws.Cells[yourRow, firsColumn], ws.Cells[yourRow, lastColumn]];
Excel.Range xlRng = ws.Range[ws.Cells[1, 1], ws.Cells[1, 4]]; // ws.Range["A1:D1"];
xlRng.FormulaR1C1 = "=MATCH(R[-1]C,Sheet2!R2C2:$R5C2,0)";
// Below is how you can get full address for your list if it's in different workbook and replace Sheet2!R2C2:$R5C2 with rangeFullAddress
// string rangeFullAddress = xlRng.Address[true,true,Excel.XlReferenceStyle.xlR1C1,true];
xlRng.Calculate();
xlRng.Value = xlRng.Value;
After this you can just sort your data using Excel Sort by 1st row. After sorting your 1st row it would look like this: 1, 2, 3, 4. Then clear data on 1st row ws.Range["A1:D1"].Clear();.
Your sort key would be Key1: ws.Range["A1:D1"], here is c# sort example using c# to sort a column in excel only change Excel.XlSortOrientation and adjust for your range.
There are other ways to sort but this way you'll keep individual formats, comments of each cell within your data
I missed 1 important detail - that your list is not in Excel sheet, but you can add it to Excel, perhaps in temporary workbook or right on the same sheet:
object [,] columnHeaders = new object[3,0]; // or object[0,3]; if you'd like to add into 1 row
columnHeaders[0, 0] = "Variable1";
columnHeaders[1, 0] = "Variable2";
columnHeaders[2, 0] = "Variable3";
columnHeaders[3, 0] = "Variable4";
xlRng.FormulaR1C1 = columnHeaders; // xlRng would be in the above Sheet2!R2C2:$R5C2

Auto expansion of formatted table in Excel using C#

I was trying to insert a new row at the end of a worksheet using OLEDB. The worksheet has a format table in a Range (a1:xx), with format and formula stored. But OLEDB insert does not come with any format.
I have read the post How to copy format of one row to another row in Excel with c# talking about get the format, but doesn't work for me. Also, I don't think it will get the formula.
In the Excel UI, at the lower right corner of a formatted table, a double arrow would appear, and we can drag it to expand the format table range.
Anything we could do through C#?
Thanks.
Excel.Range last = xlWS.Cells.SpecialCells(Excel.XlCellType.xlCellTypeLastCell, Type.Missing);
Excel.Range RngToCopyOri = xlWS.get_Range("A1", last).EntireRow;
Excel.Range RngToCopy = RngToCopyOri.Resize[RngToCopyOri.Rows.Count + 1, RngToCopyOri.Columns.Count]; //because insert will add only 1 row, so the range would be one row larger
Excel.Range RngToInsert = xlWS.get_Range("A1", Type.Missing).EntireRow;
RngToInsert.Insert(Excel.XlInsertShiftDirection.xlShiftDown, RngToCopy.Copy(Type.Missing));
I tried to copy Range(A1,lowerleft cell) to its original location, but nothing changed.
I tried Range.resize, autofill, autoformat. All of them has sort of problems. I finally gave up using OLEDB to insert data. Instead, i used
worksheet.UsedRange.Item[rowNo,getColumnIndex(worksheet,columnTitle)]=value
private int getColumnIndex(Excel.Worksheet sheetname, string header) {
int index=0;
Excel.Range activeRange=sheetname.UsedRange;
for (int i = 1; i <= activeRange.Columns.Count; i++) {
if (header == (string)(activeRange.Item[1,i] as Excel.Range).Value) {
index = i;
}
}
if(index==0)
throw some exception you like;
return index;
}
The getColumnIndex function aims to locate the column in SELECT [column] from...
In this way, the format table will automatically expand to the range you input the value.

Writing an Excel table to Excel using Interop

I am using Excel Interop to generate Excel Table into an xlsx file. I have a very simple table with 3 columns and no header, no totals but has 2 rows.
Now when I generate the Excel file, I use the following code
...
Range rng = worksheet.Range["$A$1:$C$2"];
ListObject lo = worksheet.ListObjects.Add(xlSrcRange, rng, Type.Missing, XlYesNoGuess.xlNo);
lo.ShowHeaders = false;
...
With the above code it generates the table with cell range A2:C3 instead of A1:C2. But any values I set in the A row are set but outside of the table.
If I set the ShowHeaders to true in the 3rd line of code above, then Excel is converting the top row as the header line and still moves the table cell range to A2:C3
Am I doing something wrong? I appreciate any and all help and guidance to fix this issue.
Thanks
Jaideep
Try this
//
//~~> Rest of your code
//
Range rng = worksheet.Range["$A$1:$C$2"];
ListObject lo = worksheet.ListObjects.Add(xlSrcRange, rng, Type.Missing, XlYesNoGuess.xlNo);
lo.ShowHeaders = false;
Excel.Range rngRowOne = worksheet.get_Range("A1", "A1");
rngRowOne.EntireRow.Delete(Excel.XlDirection.xlUp);
//
//~~> Rest of your code
//

Move to next cell in the next row in excel using c#

How can I move to the next row in Excel using C#. I'm using Office PIA v 14. When I used Range.Next property, it takes me to the cell immediately right to the range. How can I move to the next row? ie. the cell immediately below.
Range.Next returns a Range object that represents the next cell.
I'm not really the greatest expert alive but according to the documentation you should use Offset instead. http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.offset
Here is some pseudo code
var excelApp = this.Application;
int skipRows = 1;
int skipCells = 0;
var nextRange = excelApp.ActiveCell.Offset[skipRows, skipCells].Select();
Try the following code:
Range oRng = ws.get_Range(Column + (row +1), Type.Missing);
where ws is the worksheet object.

Categories