Det tog lidt tid men jeg har leget lidt med det.
Og jeg endte med at dele det lidt op i.s.f. at forsøge at lave alt i et gennemløb.
Kode:
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
namespace ExcelEater
{
public class Program
{
public static void StripEmptyRows(List<List<string>> data)
{
for(int rownum = data.Count - 1; rownum >= 0; rownum--)
{
if(data[rownum].All(val => val == ""))
{
data.RemoveAt(rownum);
}
}
}
public static void StripEmptyCols(List<List<string>> data)
{
for(int colnum = data[0].Count - 1; colnum >=0; colnum--)
{
if(Enumerable.Range(0, data.Count - 1).All(rownum => data[rownum][colnum] == ""))
{
foreach(List<string> row in data)
{
row.RemoveAt(colnum);
}
}
}
}
public static void Crop(List<List<string>> data)
{
StripEmptyRows(data);
StripEmptyCols(data);
}
public static int TopHeaderRows(List<List<string>> data)
{
int res = 0;
while(res < data.Count && data[res].All(val => val == "" || char.IsLetter(val[0])))
{
res++;
}
return res;
}
public static int LeftHeaderCols(List<List<string>> data)
{
int res = 0;
while(res < data[0].Count && Enumerable.Range(0, data.Count).All(rownum => data[rownum][res] == "" || char.IsLetter(data[rownum][res][0])))
{
res++;
}
return res;
}
public static void FillRows(List<List<string>> data, int nrowhdr, int ncolhdr)
{
for(int rownum = 0; rownum < nrowhdr; rownum++)
{
string last = "";
for(int colnum = ncolhdr; colnum < data[rownum].Count; colnum++)
{
if(data[rownum][colnum] == "")
{
data[rownum][colnum] = last;
}
last = data[rownum][colnum];
}
}
}
public static void FillCols(List<List<string>> data, int nrowhdr, int ncolhdr)
{
for(int colnum = 0; colnum < ncolhdr; colnum++)
{
string last = "";
for(int rownum = nrowhdr; rownum < data.Count; rownum++)
{
if(data[rownum][colnum] == "")
{
data[rownum][colnum] = last;
}
last = data[rownum][colnum];
}
}
}
public static void Fill(List<List<string>> data, int nrowhdr, int ncolhdr)
{
FillRows(data, nrowhdr, ncolhdr);
FillCols(data, nrowhdr, ncolhdr);
}
public static void Process(List<List<string>> data, int nrowhdr, int ncolhdr, Action<List<string>, List<string>, string> proc)
{
for(int rownum = nrowhdr; rownum < data.Count; rownum++)
{
for(int colnum = ncolhdr; colnum < data[rownum].Count; colnum++)
{
proc(data[rownum].Take(ncolhdr).ToList(), Enumerable.Range(0, nrowhdr).Select(rn => data[rn][colnum]).ToList(), data[rownum][colnum]);
}
}
}
public static List<List<string>> Load(string fnm)
{
List<List<string>> res = new List<List<string>>();
using(OleDbConnection con = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fnm + ";Extended Properties=\"Excel 12.0 Xml;HDR=NO;IMEX=1\";" ))
{
con.Open();
using(OleDbCommand cmd = con.CreateCommand())
{
cmd.CommandText = "SELECT * FROM [Sheet1$]";
cmd.Connection = con;
using(OleDbDataReader rdr = cmd.ExecuteReader())
{
while(rdr.Read())
{
List<string> row = new List<string>();
for(int fldnum = 0; fldnum < rdr.FieldCount; fldnum++)
{
row.Add(rdr.GetValue(fldnum).ToString());
}
res.Add(row);
}
}
}
}
return res;
}
public static void Dump(string label, List<List<string>> data)
{
Console.WriteLine("{0}:", label);
foreach(List<string> row in data)
{
foreach(string val in row)
{
Console.Write("{0,5}", val);
}
Console.WriteLine();
}
}
public static void Main(string[] args)
{
List<List<string>> data = Load(@"C:\Work\skel.xlsx");
Dump("After Load", data);
Crop(data);
Dump("After Crop", data);
int nrowhdr = TopHeaderRows(data);
int ncolhdr = LeftHeaderCols(data);
Fill(data, nrowhdr, ncolhdr);
Dump("After Fill", data);
Process(data, nrowhdr, ncolhdr, (rowhdrs,colhdrs,val) => { Console.WriteLine("({0}) ({1}) : {2}", string.Join(",", rowhdrs), string.Join(",", colhdrs),val); });
Console.ReadKey();
}
}
}
Output fra mit eksempel:
After Load:
c1 c2
c11 c12 c21 c22
c111 c112 c121 c122 c211 c212 c221 c222
r1 r11 r111 1 2 3 4 5 6 7 8
r112 9 10 11 12 13 14 15 16
r12 r121 17 18 19 20 21 22 23 24
r122 25 26 27 28 29 30 31 32
r2 r21 r211 33 34 35 36 37 38 39 40
r212 41 42 43 44 45 46 47 48
r22 r221 49 50 51 52 53 54 55 56
r222 57 58 59 60 61 62 63 64
After Crop:
c1 c2
c11 c12 c21 c22
c111 c112 c121 c122 c211 c212 c221 c222
r1 r11 r111 1 2 3 4 5 6 7 8
r112 9 10 11 12 13 14 15 16
r12 r121 17 18 19 20 21 22 23 24
r122 25 26 27 28 29 30 31 32
r2 r21 r211 33 34 35 36 37 38 39 40
r212 41 42 43 44 45 46 47 48
r22 r221 49 50 51 52 53 54 55 56
r222 57 58 59 60 61 62 63 64
After Fill:
c1 c1 c1 c1 c2 c2 c2 c2
c11 c11 c12 c12 c21 c21 c22 c22
c111 c112 c121 c122 c211 c212 c221 c222
r1 r11 r111 1 2 3 4 5 6 7 8
r1 r11 r112 9 10 11 12 13 14 15 16
r1 r12 r121 17 18 19 20 21 22 23 24
r1 r12 r122 25 26 27 28 29 30 31 32
r2 r21 r211 33 34 35 36 37 38 39 40
r2 r21 r212 41 42 43 44 45 46 47 48
r2 r22 r221 49 50 51 52 53 54 55 56
r2 r22 r222 57 58 59 60 61 62 63 64
(r1,r11,r111) (c1,c11,c111) : 1
(r1,r11,r111) (c1,c11,c112) : 2
(r1,r11,r111) (c1,c12,c121) : 3
(r1,r11,r111) (c1,c12,c122) : 4
(r1,r11,r111) (c2,c21,c211) : 5
(r1,r11,r111) (c2,c21,c212) : 6
(r1,r11,r111) (c2,c22,c221) : 7
(r1,r11,r111) (c2,c22,c222) : 8
(r1,r11,r112) (c1,c11,c111) : 9
(r1,r11,r112) (c1,c11,c112) : 10
(r1,r11,r112) (c1,c12,c121) : 11
(r1,r11,r112) (c1,c12,c122) : 12
(r1,r11,r112) (c2,c21,c211) : 13
(r1,r11,r112) (c2,c21,c212) : 14
(r1,r11,r112) (c2,c22,c221) : 15
(r1,r11,r112) (c2,c22,c222) : 16
(r1,r12,r121) (c1,c11,c111) : 17
(r1,r12,r121) (c1,c11,c112) : 18
(r1,r12,r121) (c1,c12,c121) : 19
(r1,r12,r121) (c1,c12,c122) : 20
(r1,r12,r121) (c2,c21,c211) : 21
(r1,r12,r121) (c2,c21,c212) : 22
(r1,r12,r121) (c2,c22,c221) : 23
(r1,r12,r121) (c2,c22,c222) : 24
(r1,r12,r122) (c1,c11,c111) : 25
(r1,r12,r122) (c1,c11,c112) : 26
(r1,r12,r122) (c1,c12,c121) : 27
(r1,r12,r122) (c1,c12,c122) : 28
(r1,r12,r122) (c2,c21,c211) : 29
(r1,r12,r122) (c2,c21,c212) : 30
(r1,r12,r122) (c2,c22,c221) : 31
(r1,r12,r122) (c2,c22,c222) : 32
(r2,r21,r211) (c1,c11,c111) : 33
(r2,r21,r211) (c1,c11,c112) : 34
(r2,r21,r211) (c1,c12,c121) : 35
(r2,r21,r211) (c1,c12,c122) : 36
(r2,r21,r211) (c2,c21,c211) : 37
(r2,r21,r211) (c2,c21,c212) : 38
(r2,r21,r211) (c2,c22,c221) : 39
(r2,r21,r211) (c2,c22,c222) : 40
(r2,r21,r212) (c1,c11,c111) : 41
(r2,r21,r212) (c1,c11,c112) : 42
(r2,r21,r212) (c1,c12,c121) : 43
(r2,r21,r212) (c1,c12,c122) : 44
(r2,r21,r212) (c2,c21,c211) : 45
(r2,r21,r212) (c2,c21,c212) : 46
(r2,r21,r212) (c2,c22,c221) : 47
(r2,r21,r212) (c2,c22,c222) : 48
(r2,r22,r221) (c1,c11,c111) : 49
(r2,r22,r221) (c1,c11,c112) : 50
(r2,r22,r221) (c1,c12,c121) : 51
(r2,r22,r221) (c1,c12,c122) : 52
(r2,r22,r221) (c2,c21,c211) : 53
(r2,r22,r221) (c2,c21,c212) : 54
(r2,r22,r221) (c2,c22,c221) : 55
(r2,r22,r221) (c2,c22,c222) : 56
(r2,r22,r222) (c1,c11,c111) : 57
(r2,r22,r222) (c1,c11,c112) : 58
(r2,r22,r222) (c1,c12,c121) : 59
(r2,r22,r222) (c1,c12,c122) : 60
(r2,r22,r222) (c2,c21,c211) : 61
(r2,r22,r222) (c2,c21,c212) : 62
(r2,r22,r222) (c2,c22,c221) : 63
(r2,r22,r222) (c2,c22,c222) : 64