To help people to get start with programing Excel in Fsharp, I will show several common scenarios for reading and writing data from and to excel spreadsheet. The scenarios are:
Example file Input.xlsx:
Example 0: Opening an exiting\Creating a new excel worksheet
// read and write data to\from a excel workbook
// Start Excel, Open a exiting file for input and create a new file for output
let xlApp = new Excel.ApplicationClass()
let xlWorkBookInput = xlApp.Workbooks.Open(@"C:\Users\jackhu\Desktop\Input.xlsx")
let xlWorkBookOutput = xlApp.Workbooks.Add()
xlApp.Visible <- true
// Open input's 'Sheet1' and create a new worksheet in output.xlsx
let xlWorkSheetInput = xlWorkBookInput.Worksheets.["Sheet1"] :?> Excel.Worksheet
let xlWorkSheetOutput = xlWorkBookOutput.Worksheets. :?> Excel.Worksheet
xlWorkSheetOutput.Name <- "OutputSheet1"
First, I make reference to office interop dlls. I open an exiting excel workbook for input and create a new workbook for output by calling Workbooks.Open and Workbooks.Add(). The xlApp.Visible <- true property is set to display the workbooks. I then find the “Sheet1” from the input workbook by calling Worksheets.["Sheet1"]and get the first worksheet from the output worksheet by indexing Worksheets. into it.
Example 1: Reading\Writing a cell value
// EXAMPLE 1: Reading\Writing a cell value using cell index
let value1 = xlWorkSheetInput.Cells.[10,5]
xlWorkSheetOutput.Cells.[10,5] <- value1
// EXAMPLE 1.1: Reading\Writing a cell value using range
let value2 = xlWorkSheetInput.Cells.Range("E10","E10").Value2
xlWorkSheetOutput.Cells.Range("E10","E10").Value2 <- value2
I show two ways of accessing a cell value. One method is by using array indexer. Inheriting from VB array indexing convention, the Excel indexer starts from 1 instead from 0. Another method is using the Range by specifying the starting cell location and ending cell location. In my example, since I only have one cell, E10 is used for both the starting and the ending position.
Example 2: Reading\Writing a row
// EXAMPLE 2: Reading\Writing a row
let row = xlWorkSheetInput.Cells.Rows. :?> Excel.Range
(xlWorkSheetOutput.Cells.Rows. :?> Excel.Range).Value2 <- row.Value2
In above code snippet, I use :?> to up-cast object to Excel range type, so that I gets intellisense\error checking support for the row value. To figure out the exact code, I also used the debugger to exampling the values to help me figuring out the correct type casting.
Example 3: Reading\Writing a column
// EXAMPLE 3: Reading\Writing a column
let column1 = xlWorkSheetInput.Cells.Range("A:A")
xlWorkSheetOutput.Cells.Range("A:A").Value2 <- column1.Value2
Similar to the row example, we can also use a column index to select a range xlWorkSheetInput.Cells.Columns. :?> Excel.Range. Instead, I use the range parameter “A:A” for the column ( I may use “1:1” is for a row).
Example 4: Reading\Writing a Range
// EXAMPLE 4: Reading\Writing a Range
let inputRange = xlWorkSheetInput.Cells.Range("A1","E10")
for i in 1 .. inputRange.Cells.Rows.Count do
for j in 1 .. inputRange.Cells.Columns.Count do
xlWorkSheetOutput.Cells.[i,j] <- inputRange.[i,j]
Of course, there are many other ways to read and write a large range of the data. Here, I show how a two nested for loops for iterate through the worksheet as a 2D array.
Example 5: Writing a Jagged array
// EXAMPLE 5: Writing an Jagged arrays
let data = [| [|0 .. 1 .. 2|];
[|0 .. 1 .. 4|];
[|0 .. 1 .. 6|] |]
for i in 1 .. data.Length do
for j in 1 .. data.[i-1].Length do
xlWorkSheetOutput.Cells.[j, i] <- data.[i-1].[j-1]
When your data does not conform to M by N size, the jagged array is a more practical approach. I hope a few simple examples can help you to get started with excel. Happy coding!
Following up with the recent announcement on F# EasyChart, I like to point out a few .net charting libraries that can potentially be applied to the interactive development environment like the F# FSI window.
In this blog, I also like to demonstrate how to call Excel chart libraries from the FSI window. There are several benefits for using the excel charts from FSI
Step0: Software Setup
Step1: Past in following code in FSI
#r "Microsoft.Office.Interop.Excel" #r "office" open Microsoft.Office.Interop let dataX = [|0.0 .. 0.1 .. 10.|] let dataY = [| [|for f in dataX -> cos f|]; [|for f in dataX -> sin f|] |] // Update the excel charting object let xlApp = new Excel.ApplicationClass() let xlWorkBook = xlApp.Workbooks.Add() let xlWorkSheet = xlWorkBook.Worksheets. :?> Excel.Worksheet let xlCharts = xlWorkSheet.ChartObjects() :?> Excel.ChartObjects let xlChart = xlCharts.Add(1., 1., 460., 380.) let myChart = xlChart.Chart // Fill in a excel worksheet with data from dataY for i in 1 .. dataY.Length do for j in 1 .. dataY.[i-1].Length do xlWorkSheet.Cells.[j, i] <- dataY.[i-1].[j-1] let xlRange = xlWorkSheet.Cells.CurrentRegion myChart.SetSourceData(xlRange) // Set Plot type and show chart myChart.ChartType <- Excel.XlChartType.xlXYScatterLines xlApp.Visible <- true
let dataX = [|0.0 .. 0.1 .. 10.|]
let dataY = [| [|for f in dataX -> cos f|];
[|for f in dataX -> sin f|] |]
// Update the excel charting object
let xlWorkBook = xlApp.Workbooks.Add()
let xlWorkSheet = xlWorkBook.Worksheets. :?> Excel.Worksheet
let xlCharts = xlWorkSheet.ChartObjects() :?> Excel.ChartObjects
let xlChart = xlCharts.Add(1., 1., 460., 380.)
let myChart = xlChart.Chart
// Fill in a excel worksheet with data from dataY
for i in 1 .. dataY.Length do
for j in 1 .. dataY.[i-1].Length do
xlWorkSheet.Cells.[j, i] <- dataY.[i-1].[j-1]
let xlRange = xlWorkSheet.Cells.CurrentRegion
// Set Plot type and show chart
myChart.ChartType <- Excel.XlChartType.xlXYScatterLines
It result in:
FSharp language services Intellisense fairly useful to select a right chart.
While I am working on compiling a list of .Net math libraries, I found a simple way to call Excel math library from F# FSI. In the following example, I will show how to use Excel’s Median, StDev and MInverse functions from F# scripting environment (FSI).
Software setup: VS2010 Sp1 with Office 2010 installed.
There are few benefits of using Excel math libraries:
but, there are also issues:
Both F# and C# Code example @ http://code.msdn.microsoft.com/Calling-Excel-Math-6b811836
As the word “code-first” implies, the EF 4.1 offers a code centric data programming paradigm. From a coder’s point of view, it requires little effort to map a very clean object model to a database. This style of programming is idea for explorative, bottom-up kind fsharp programmers. Since EF 4 CTP4 release, there have already been many buzzes. The following two blogs have in-depth EF 4.1 feature overview.
In this blog, I demonstrate how to use EF 4.1 Code-first in Fsharp 2.0 to save a record into a SQL CE. I also provide workarounds for several practical issues may block fsharp programmers.
Step0: Install Software Packages
Step1: Create a New F# Application
Add Project references: Unlike C#, Fsharp compiler requires additional references from System.Data and System.Data.Entity to resolve base types inherited by EF 4.1
The EntityFramework.dll is under $\Program Files (x86)\Microsoft ADO.NET Entity Framework Feature CTP5\Binaries\EntityFramework.dll
Step2: Create a Model
In this example, I create a CLCars class. The class contains a single DbSet of Cars. In Car class I have a field of ID (serve as the primary key) and a field of Name.
In the driver code, I create a new CLCars database, added a Car to it and flush out to the database.
Step3: Pointing to a Database
I love SQL CE 4.0, especially because user no longer needs to generate a primary key while adding a record. Yeah! In this example, I add an app.config file and embed the database connection string. I also make sure the connectionString Name property is the same as my DbContext class name, so that the EF 4.1 automatically generates a database at runtime.
Step4: Run and Verify data
After build and run app, I use SQL Server Compact 4.0 Tooling for VS2010 to verify the database, the table and the data are added correctly.
During the ad-hocking, I also encountered several issues. Here is how I work around them.
Issue#1: EF 4.1 does not support nested type; the model can NOT be used inside a Module or a Script
Trying to put the model inside a module, I got a run time exception: “The type 'Program+Car' is not a supported entity type.”
Digging into fsharp assembly using reflector, we can see the Fsharp script and module generate a nested-type which is not supported in EF 4.1
The work around is to put the model code inside a namespace DataModel
The VB module shares the same limitation. The work around in below example is to move the Car and CLCars class outside the Module1.
Issue#2: Property initialization on DBContext class need to use [<DefaultValue>] attribute with Explicit Fields
During EF DbContext construction, it will reflect on all its properties and initialized them with database mapping values. After base construction, if the inhered Fsharp class calls its constructor with property initialization, it will override the property value that base class already initialized.
In the following example, the DbContext constructor will initialize m_cars to a DbSet<Car> mapping value, but the inhered CLCars constructor will reinitialize n_cars to NULL. This could cause a NullReferenceException at runtime.
EF 4.1 code-first is a great tool for F# 2.0 data programming. As Fsharp 3.0 features become clearer in the next few months, I am supper exited and feel good about them. I expect Fsharp 3.0 will take these experiences to the next level. Happy coding!
Code example is published @ http://code.msdn.microsoft.com/F-Code-First-Development-326dede1