2012-08-29 26 views
5

बनाने के लिए एक्सेल कोशिकाओं की एक सूची को सरल बनाएं मैं सेल संदर्भों की सूची से Excel.Range ऑब्जेक्ट बनाना चाहता हूं जो गतिशील रूप से जेनरेट किए गए हैं।रेंज

Excel.Range outputRange = sheet.get_Range(strCellRange, Type.Missing); 

चूंकि strCellRange काफी बड़ा हो सकता है, यह कॉम अपवाद देता है। इसलिए मैं इसे यूनियन के साथ रेंज नोटेशन के लिए सरल बनाना चाहता हूं।

उदा

string strCellRange = "F2,G2,H2,I2,J2,K2,L2,F7,G7,H7,I7,J7,K7,L7,F12,G12,H12,I12,J12,K12,L12,F17,G17,H17,I17,J17,K17,L17,F22,G22,H22,I22,J22,K22,L22,F27,G27,H27,I27,J27,K27,L27"; 

string strCellRange = "F2:L2,F7:L7,F12:L12,F17:L17,F22:L22,F27:L27"; 
  1. को

    वहाँ कक्ष संदर्भ का बहुत कुछ के साथ एक रेंज वस्तु बनाने के लिए किसी भी एक्सेल विधि है?

  2. क्या उपरोक्त सरलीकरण (एक मैट्रिक्स एल्गोरिदम) प्राप्त करने के लिए कोई ज्ञात एल्गोरिदम है?
+0

एक्सेल वीबीए में आप 1 और 2 को पूरा करने के लिए 'संघ' का उपयोग करेंगे। मैं इस बारे में चिंतित हूं कि कैसे - या अगर - आप इसे 'सी # ' – brettdj

+0

@brettdj के माध्यम से प्राप्त कर सकते हैं: हाँ मैं एप्लिकेशन का उपयोग कर सकता हूं। यूनियन (, )। लेकिन मेरी मूल स्ट्रिंग में AFAIK अल्पविराम "," यूनियन ऑपरेटर भी है। –

+0

नीचे मेरा अपडेट देखें। आरजीडीएस – brettdj

उत्तर

3

गायन,

VBA में आप

Sub Test() 
Dim rng1 As Range 
Dim strCellRange As String 
strCellRange = "F2,G2,H2,I2,J2,K2,L2,F7,G7,H7,I7,J7,K7,L7,F12,G12,H12,I12,J12,K12,L12,F17,G17,H17,I17,J17,K17,L17,F22,G22,H22,I22,J22,K22,L22,F27,G27,H27,I27,J27,K27,L27" 
Set rng1 = Range(strCellRange) 
Set rng1 = Union(rng1, rng1) 
Debug.Print rng1.Address 
End Sub 
+0

+1 जुटाने की कोशिश कर बायपास करने के लिए सिर्फ एक तरीका है। अच्छा और सरल – shahkalpesh

+0

ठीक है, लेकिन ओपी की समस्या यह तथ्य है कि स्ट्रिंग में दिए गए रेंज की पीढ़ी स्ट्रिंग में सेल्स की संख्या के कारण अपवाद उत्पन्न करती है ... –

+0

@brettdj: आपने सरलीकरण की मेरी समस्या का उत्तर दिया, अब मैं स्वयं ले सकता हूं जब भी सेल सीमा आती है संघ। अंततः मैं सरलीकृत संस्करण के साथ एक और सीमा भी मार सकता हूं, लेकिन फिर मैं तोड़ सकता हूं और अलग-अलग श्रेणियां कर सकता हूं। –

0

मुझे लगता है कि कक्ष संदर्भ की लंबी दूरी को पुनः प्राप्त करने के लिए किसी भी विधि है न। मैं कोडिंग के माध्यम से पूर्ण शीट लेना और उसके साथ नेविगेट करना पसंद करूंगा।

1

VBA

Function Unionize(src As Range) As Range 
Dim cell As Range 
Dim unionizedRange As Range 

For Each cell In src 
    If unionizedRange Is Nothing Then 
     Set unionizedRange = cell 
    Else 
     Set unionizedRange = Union(unionizedRange, cell) 
    End If 
Next 

Set Unionize = unionizedRange 
End Function 

C#

Excel.Range Unionize(Excel.Range src) 
{ 
    Excel.Range unionizedRange; 

    foreach (Excel.Range cell in src) 
    { 
     if (unionizedRange == null) 
     { 
      unionizedRange = cell; 
     } 
     Else 
     { 
      unionizedRange = Application.Union(unionizedRange, cell); 
     } 
    } 
    return unionizedRange; 
} 

संपादित (किसी न किसी तरह कट, यह वाक्य रचना के लिए संकलक के माध्यम से नहीं चला): @ brettdj के समाधान

के आधार पर
Excel.Range outputRange = sheet.get_Range(strCellRange, Type.Missing); 
strCellRange = Application.Union(outputRange, outputRange).Address(false, false); 
+0

शामिल छोटा versionof strCellRange ओपी के लक्ष्य नहीं है। यह तथ्य यह है कि रेंज मूल स्ट्रिंग से एक अपवाद –

2

साथ एक श्रृंखला के लिए अपने प्रत्यक्ष स्ट्रिंग के लिए मजबूर कर सकता है यह एक प्रारंभिक बिंदु हो सकता है (यह जेड परे स्तंभों के लिए काम नहीं करता है, और आयतों की पहचान नहीं करता):

private string CompactRangeStringByRows(string strCellRange) 
    { 
     SortedDictionary<int, SortedList<char, char>> rows = new SortedDictionary<int, SortedList<char, char>>(); 
     foreach (string aCell in strCellRange.Split(new Char[] { ',' })) 
     { 
      char col = aCell[0]; 
      int row = int.Parse(aCell.Substring(1, aCell.Length - 1)); 
      SortedList<char, char> cols; 
      if (!rows.TryGetValue(row, out cols)) 
      { 
       cols = new SortedList<char, char>(); 
       rows[row] = cols; 
      } 
      cols.Add(col, col); 
     } 
     StringBuilder sb = new StringBuilder(); 
     bool first = true; 
     foreach (KeyValuePair<int, SortedList<char, char>> rowCols in rows) 
     { 
      char minCol = '0'; 
      char maxCol = '0'; 
      foreach (char col in rowCols.Value.Keys) 
      { 
       if (minCol == '0') 
       { 
        minCol = col; 
        maxCol = col; 
       } 
       else 
       { 
        if (col == maxCol + 1) 
         maxCol = col; 
        else 
        { 
         AddRangeString(sb, first, rowCols.Key, minCol, maxCol); 
         minCol = col; 
         maxCol = col; 
         first = false; 
        } 
       } 
      } 
      AddRangeString(sb, first, rowCols.Key, minCol, maxCol); 
      first = false; 
     } 
     return sb.ToString(); 
    } 

    private void AddRangeString(StringBuilder sb, bool first, int row, char minCol, char maxCol) 
    { 
     if (!first) 
      sb.Append(','); 
     sb.Append(minCol); 
     sb.Append(row); 
     if (maxCol != minCol) 
     { 
      sb.Append(':'); 
      sb.Append(maxCol); 
      sb.Append(row); 
     } 
    } 
+0

इस हो जाएगा प्रदान की सबसे बढ़िया उत्तर। बहुत उपयोगी +1। मैं R1C1 शैली के साथ कक्ष संदर्भ उत्पन्न कर सकते हैं। या यहां तक ​​कि (पंक्ति^कोल) जो एल्गोरिदम को बहुत उपयोगी बना देगा। समय पर अनुमति मिलने पर निश्चित रूप से यह कोशिश करेंगे। लेकिन अभी के लिए मुझे लगता है कि ब्रेट्डज का समाधान ठीक है। –

+0

श्रेणी में रेखाओं और आयतों को "मैन्युअल रूप से" प्राप्त करने के लिए एक समान एल्गोरिदम विकसित किया। नीचे मेरा जवाब देखें। –

1

पहले कुछ वर्गों संदर्भ पकड़े है ...

public class CellRef : IEquatable<CellRef> 
{ 
    public int Row { get; private set; } 
    public int Col { get; private set; } 

    // some more code... 
} 

public class CellRange : IEquatable<CellRange> 
{ 
    public CellRef Start { get; private set; } 
    public CellRef Stop { get; private set; } 

    // some more code... 
} 

फिर एल्गोरिदम और विधि ... इस विधि को पार करने से पहले कोशिकाओं की सूची को सूची में रखा जाना चाहिए और सॉर्ट किया जाना चाहिए।

public static string GetSimplifiedRangeString(List<CellRef> cellList) 
    { 
     #region Column wise simplify (identify lines) 

     Dictionary<CellRef, CellRef> rowRanges = new Dictionary<CellRef, CellRef>(new CellRefEqualityComparer()); 

     int currentRangeStart = 0; 
     for (int currentRangeStop = 0; currentRangeStop < cellList.Count; currentRangeStop++) 
     { 
      CellRef currentCell = cellList[currentRangeStop]; 
      CellRef previousCell = (currentRangeStop == 0) ? null : cellList[currentRangeStop - 1]; 

      bool cont = IsContigousX(currentCell, previousCell); 

      if (!cont) 
      { 
       currentRangeStart = currentRangeStop; 
      } 

      if (!rowRanges.ContainsKey(cellList[currentRangeStart])) 
       rowRanges.Add(cellList[currentRangeStart], cellList[currentRangeStop]); 
      else 
       rowRanges[cellList[currentRangeStart]] = cellList[currentRangeStop]; 
     } 

     #endregion 


     #region Row wise simplify (identify rectangles) 

     List<CellRange> rangeList = new List<CellRange>(); 
     foreach (KeyValuePair<CellRef, CellRef> range in rowRanges) 
     { 
      rangeList.Add(new CellRange(range.Key, range.Value));     
     }    
     Dictionary<CellRange, CellRange> colRanges = new Dictionary<CellRange, CellRange>(new CellRangeEqualityComparer()); 

     currentRangeStart = 0; 
     for (int currentRangeStop = 0; currentRangeStop < rangeList.Count; currentRangeStop++) 
     { 
      CellRange currentCellRange = rangeList[currentRangeStop]; 
      CellRange previousCellRange = (currentRangeStop == 0) ? null : rangeList[currentRangeStop - 1]; 

      bool cont = IsContigousY(currentCellRange, previousCellRange); 

      if (!cont) 
      { 
       currentRangeStart = currentRangeStop; 
      } 

      if (!colRanges.ContainsKey(rangeList[currentRangeStart])) 
       colRanges.Add(rangeList[currentRangeStart], rangeList[currentRangeStop]); 
      else 
       colRanges[rangeList[currentRangeStart]] = rangeList[currentRangeStop]; 
     } 

     #endregion 


     #region Simplify ranges (identify atomic lines and rectangles) 

     StringBuilder retStr = new StringBuilder(); 
     foreach (KeyValuePair<CellRange, CellRange> ranges in colRanges) 
     { 
      string rangePart = string.Empty; 
      if (ranges.Key.Equals(ranges.Value)) 
      { 
       if (ranges.Key.Start.Equals(ranges.Key.Stop)) 
       { 
        rangePart = ranges.Key.Start.ToString(); 
       } 
       else 
       { 
        rangePart = ranges.Key.ToString(); 
       } 
      } 
      else 
      { 
       rangePart = new CellRange(ranges.Key.Start, ranges.Value.Stop).ToString(); 
      } 

      if (retStr.Length == 0) 
      { 
       retStr.Append(rangePart); 
      } 
      else 
      { 
       retStr.Append("," + rangePart); 
      } 
     } 

     return retStr.ToString(); 

     #endregion 
    } 

    /// <summary> 
    /// Checks whether the given two cells represent a line. 
    /// </summary> 
    /// <param name="currentCell">Line start</param> 
    /// <param name="previousCell">Line end</param> 
    /// <returns></returns> 
    private static bool IsContigousX(CellRef currentCell, CellRef previousCell) 
    { 
     if (previousCell == null) 
      return false; 
     return (currentCell.Row == previousCell.Row) && (currentCell.Col == (previousCell.Col + 1)); 
    } 

    /// <summary> 
    /// Checks whether the given two cells represents a rectangle. 
    /// </summary> 
    /// <param name="currentCellRange">Top-left cell</param> 
    /// <param name="previousCellRange">Bottom-right cell</param> 
    /// <returns></returns> 
    private static bool IsContigousY(CellRange currentCellRange, CellRange previousCellRange) 
    { 
     if (previousCellRange == null) 
      return false; 

     bool sameVertically = (currentCellRange.Start.Col == previousCellRange.Start.Col) && (currentCellRange.Stop.Col == previousCellRange.Stop.Col); 
     bool contigous = (currentCellRange.Start.Row == currentCellRange.Stop.Row) && (previousCellRange.Start.Row == previousCellRange.Stop.Row) && ((previousCellRange.Stop.Row + 1) == currentCellRange.Stop.Row); 
     return sameVertically && contigous; 
    } 

उम्मीद है कि यह किसी की सहायता करेगा।

संबंधित मुद्दे