Sounds like a good use for stash. Capture the matrix (or the entire entry, it's up to you). The following assumes you know how to capure and set a list with stash, ie:
{exp:stash:set_list name="matrix_block"}
<!-- Capture the matrix to a list -->
{matrix_field}
{stash:day}{day}{/stash:day} <!-- The day -->
{stash:col_1}{event_1}{/stash:col_1} <!-- Value 1 -->
{stash:col_2}{event_2}{/stash:col_2}
{/matrix_field}
{/exp:stash:set_list}
<!-- Now we have a list, duplicate it and create new list using only the days -->
{exp:stash:split_list
name="daysofweek"
list="matrix_block"
match="#[a-zA-Z]#"
against="day"
}
<!-- Now out put the sucker -->
{exp:stash:parse} <!-- Make sure everything else is set before trying to target data -->
{exp:stash:get_list name="daysofweek" unique="day" require_prefix="yes" prefix="out" } <!--
Get the days from our duplicated list, using unique="" makes sure we dont get duplicate days,
force prefix so inner get_list doesn't bork -->
<li>{out:day} <!-- The unique day -->
{exp:stash:get_list:sub name="matrix_block" match="#^{out:day}$#" against="day" parse="inward" }<!--
Get the full list, match the contents 'day' against the day in this list -->
<ul>
<li>{col_1} {col_2}</li>
</ul>
{/exp:stash:get_list:sub}
</li>
{/exp:stash:get_list}
{/exp:stash:parse}
Mae sure your Stash is up-to-date. Tested locally with hard coded list and works fine.
Update:
stash:get_list:sub
is used when you're inside a get_list already. I used sub but could be elephant.
'raw' refers to the initial set_list name, updated code I mistakenly used raw instead of matrix_block