share
Stack OverflowHow to create list splitted by columns?
[-2] [5] omoto
[2009-05-30 15:57:20]
[ c# asp.net asp.net-mvc logic ]
[ http://stackoverflow.com/questions/930013] [DELETED]

How to implement splitting by columns alpha ordered list as shown on the picture?

?

(4) How to clarify this post? - A. Levy
(2) Take the red pill. The tags are as all over the place as the question. How often do you see weblogic and c# on the same question? Wacky. - duffymo
Checkout please modified question. - omoto
(3) This question wasn't very clear, but I don't see how it's "not a real question". Anyways, the author made it more clear. I'm voting to reopen. - Zifre
(3) I agree with Zifre, should be reopen. - Raf
Do you mean A matrix, or THE matrix? - Christoffer
Using the word "matrix" is probably inappropriate here, since people are probably expecting some math rather than a rendering exercise. - Chris Farmer
[+1] [2009-05-30 17:38:19] fortran

I think you mean something like this:

items = sorted(file("items.txt").readlines())

current = ""
clines = 0
maxlines = 50

print "<table><tr><td>"
for i in items:
    if i[0].upper() != current:
    	current = i[0].upper()
    	print "<h1>", current, "</h1>"
    clines += 1
    if clines >= maxlines:
    	print "</td></td>"
    	clines = 0
    print i

print "</td></tr></table>"

Surely the HTML sucks, but that's the idea, when you exceed the maximum lines per column, switch to the next column.

If you want to make sure that a column always starts with a heading, then you should switch to the next column when the current number of lines plus the size of the next group exceeds the maximum number of lines per column.


One requirement I should include all letters to this list, in your sample if I right understand it's impossible if items.txt will be without any letter - omoto
It's easy to add a check for that and add the missing headings... just check the ordinal number of the letters to see if they're consecutive or not. - fortran
1
[0] [2009-05-30 18:26:08] GalacticCowboy

I would probably approach it in the following manner:

  1. If the input list is unsorted, find a technique (LINQ, etc.) to group and sort your item groups and items. That doesn't really seem to be your question here, although I'm open to correction - there are dozens of techniques for doing that, so it should be a popular question on its own...
  2. Identify the number of desired columns. We could even try different numbers of columns later in the algorithm, to try to get "best-fit".
  3. Divide the total number of detail items (possibly including the headers as well - I'm designing this on my feet...) by the number of columns. This will be the approximate number of items we want in each column.
  4. Starting from the left, place items into the column until adding another group would run over the number of items per column. (probably need to consider the possibility of one freakishly-large group that fills an entire column by itself...) At this point, we need to decide whether the next group goes in this column or the next one. I'd suggest something like this: if the break point within this group is in the upper half - i.e. more items in the group would be below the desired cut-off line than above it - go to the next column. Otherwise, add the group to the current column. Obviously if we are in the last column, there is no "next" column so we just add it to this one.

The hope is that using this technique - allowing each column to overflow slightly - will balance out over time and space. Otherwise, we just keep pushing groups to the next column and our final column ends up significantly longer than the others.


2
[0] [2009-05-30 18:53:02] omoto [ACCEPTED]

Done, thanks a lot to fortran and others.

Here comes solution that is acceptable for me

public ActionResult Test()
{    
var groupedByLetter = from l in Letters
                      join service in EntityBase.db.Services on
                      l equals service.Name[0] into grouped
                      select new ServiceInfo { 
                          Letter = l.ToStr(),
                          Services = grouped,
                          Total = grouped.Count()
                      };
                      List<string> result = new List<string>();
                      foreach (var l in groupedByLetter)
                      {
                         if (l.Services.Count() > 0)
                            result.Add(string.Format("<li><h1>{0}</h1></li>", l.Letter));
                         else
                            result.Add(string.Format("<li class='disabled'><h1>{0}</h1></li>", l.Letter));
                         foreach (var service in l.Services)
                         {
                            result.Add(string.Format("<li><a href='/service/info/{0}'>{0}</a></li>", service.Name));
                         }
                      }
                      return View(result);
}

    private static readonly char[] Letters =
    		"ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ0".ToCharArray();

And HTML rendering

<%  
			int clines = 0;
			int maxlines = Model.Count / 5;
		%>
		<% for (var i = 0; i < Model.Count; i++)
  {
	  if (clines == 0)
	  {
		%>
		<ul class="col">
			<%	
				}


			%>
			<%=Model[i]%>
			<%	
				clines += 1;
				if (clines >= maxlines)
				{
					if (Model[i + 1]!=null && Model[i+1].Contains("</a>"))
					{
						continue;
					}
			%>
		</ul>
		<%
			clines = 0;
				}
   }%>

Result Done


Looks nice, I'm glad to have been helpful :-) - fortran
3
[0] [2009-05-30 16:05:14] Richie_W

A HashMap using a String (Or even a character) as the key (Letter of the alphabet) and a array as the value.


Yes but how to split them on equal columns? - omoto
4
[0] [2009-05-30 16:05:35] WebDevHobo

Looks like a website, probably an overview.

The answer is: templates and php


5