@@ -34,8 +34,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
3434MC_EXEC_DEFINE_EVAL_METHOD (Arrays, Keys, 2 )
3535MC_EXEC_DEFINE_EVAL_METHOD(Arrays, Extents, 2 )
3636MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Combine, 4 )
37- MC_EXEC_DEFINE_EXEC_METHOD(Arrays, CombineByRow, 2 )
38- MC_EXEC_DEFINE_EXEC_METHOD(Arrays, CombineByColumn, 2 )
37+ MC_EXEC_DEFINE_EXEC_METHOD(Arrays, CombineByRowOrColumn, 3 )
3938MC_EXEC_DEFINE_EXEC_METHOD(Arrays, CombineAsSet, 3 )
4039MC_EXEC_DEFINE_EXEC_METHOD(Arrays, Split, 4 )
4140MC_EXEC_DEFINE_EXEC_METHOD(Arrays, SplitByRow, 2 )
@@ -72,7 +71,7 @@ struct array_element_t
7271
7372struct combine_array_t
7473{
75- uindex_t index;
74+ uindex_t index;
7675 array_element_t *elements;
7776};
7877
@@ -94,6 +93,56 @@ static int compare_array_element(const void *a, const void *b)
9493 return MCStringCompareTo (MCNameGetString (t_left -> key), MCNameGetString (t_right -> key), kMCStringOptionCompareExact );
9594}
9695
96+ // //////////////////////////////////////////////////////////////////////////////
97+
98+ // combine by row or column expects an integer-indexed array
99+ struct array_int_indexed_element_t
100+ {
101+ index_t key;
102+ MCValueRef value;
103+ };
104+
105+ struct combine_int_indexed_array_t
106+ {
107+ uindex_t index;
108+ array_int_indexed_element_t *elements;
109+ MCExecContext* converter;
110+ };
111+
112+ static bool list_int_indexed_array_elements (void *p_context, MCArrayRef p_array, MCNameRef p_key, MCValueRef p_value)
113+ {
114+ combine_int_indexed_array_t *ctxt;
115+ ctxt = (combine_int_indexed_array_t *)p_context;
116+
117+ MCAutoNumberRef t_key;
118+ if (ctxt -> converter -> ConvertToNumber (MCNameGetString (p_key), &t_key))
119+ {
120+ index_t t_key_num = MCNumberFetchAsInteger (*t_key);
121+
122+ if (t_key_num < 1 ) // Invalid index
123+ return false ;
124+
125+ ctxt -> elements[ctxt -> index] . key = t_key_num;
126+ ctxt -> elements[ctxt -> index] . value = p_value;
127+ ++(ctxt -> index);
128+
129+ return true ;
130+ }
131+ else
132+ return false ;
133+ }
134+
135+ static int compare_int_indexed_elements (const void *a, const void * b)
136+ {
137+ const array_int_indexed_element_t *t_left, *t_right;
138+ t_left = (const array_int_indexed_element_t *)a;
139+ t_right = (const array_int_indexed_element_t *)b;
140+
141+ return (t_left -> key - t_right -> key < 0 ) ? -1 : (t_left -> key != t_right -> key ? 1 : 0 );
142+ }
143+
144+ // //////////////////////////////////////////////////////////////////////////////
145+
97146void MCArraysExecCombine (MCExecContext& ctxt, MCArrayRef p_array, MCStringRef p_element_delimiter, MCStringRef p_key_delimiter, MCStringRef& r_string)
98147{
99148 bool t_success;
@@ -107,14 +156,14 @@ void MCArraysExecCombine(MCExecContext& ctxt, MCArrayRef p_array, MCStringRef p_
107156 t_success = MCStringCreateMutable (0 , &t_string);
108157
109158 combine_array_t t_lisctxt;
110- t_lisctxt . elements = nil;
159+ t_lisctxt . elements = nil;
111160 if (t_success)
112161 t_success = MCMemoryNewArray (t_count, t_lisctxt . elements);
113162
114163 if (t_success)
115164 {
116- t_lisctxt . index = 0 ;
117- MCArrayApply (p_array, list_array_elements, &t_lisctxt);
165+ t_lisctxt . index = 0 ;
166+ MCArrayApply (p_array, list_array_elements, &t_lisctxt);
118167 qsort (t_lisctxt . elements, t_count, sizeof (array_element_t ), compare_array_element);
119168 for (uindex_t i = 0 ; i < t_count; i++)
120169 {
@@ -151,9 +200,115 @@ void MCArraysExecCombine(MCExecContext& ctxt, MCArrayRef p_array, MCStringRef p_
151200 ctxt . Throw ();
152201}
153202
154- void MCArraysExecCombineByColumn (MCExecContext& ctxt, MCArrayRef p_array, MCStringRef& r_string)
203+ // Should be removed when 'combine by row' and 'combine by column' only differs by the delimiter used,
204+ // not by the way the array is handled - any index is fine for combine by row
205+ void MCArraysExecCombineByRow (MCExecContext& ctxt, MCArrayRef p_array, MCStringRef &r_string)
155206{
156- ctxt . Unimplemented ();
207+ MCAutoListRef t_list;
208+ MCListCreateMutable (ctxt . GetRowDelimiter (), &t_list);
209+
210+ uindex_t t_count = MCArrayGetCount (p_array);
211+ combine_array_t t_lisctxt;
212+ bool t_success;
213+
214+ t_lisctxt . elements = nil;
215+ t_lisctxt . index = 0 ;
216+ t_success = MCMemoryNewArray (t_count, t_lisctxt . elements);
217+
218+ if (t_success)
219+ {
220+ MCArrayApply (p_array, list_array_elements, &t_lisctxt);
221+ qsort (t_lisctxt . elements, t_count, sizeof (array_element_t ), compare_array_element);
222+
223+ for (int i = 0 ; i < t_count && t_success; ++i)
224+ {
225+ MCAutoStringRef t_string;
226+ if (ctxt . ConvertToString (t_lisctxt . elements[i] . value, &t_string))
227+ t_success = MCListAppend (*t_list, *t_string);
228+ else
229+ t_success = false ;
230+ }
231+
232+ MCMemoryDeleteArray (t_lisctxt . elements);
233+ }
234+
235+ if (t_success && MCListCopyAsString (*t_list, r_string))
236+ return ;
237+
238+ ctxt . Throw ();
239+ }
240+
241+ void MCArraysExecCombineByRowOrColumn (MCExecContext& ctxt, MCArrayRef p_array, bool p_is_row, MCStringRef &r_string)
242+ {
243+ if (p_is_row)
244+ {
245+ // Temporarily buggy output for 'combine by row'
246+ MCArraysExecCombineByRow (ctxt, p_array, r_string);
247+ return ;
248+ }
249+
250+ char_t t_delimiter;
251+ if (p_is_row)
252+ t_delimiter = ctxt . GetRowDelimiter ();
253+ else
254+ t_delimiter = ctxt . GetColumnDelimiter ();
255+
256+ MCAutoListRef t_list;
257+ MCListCreateMutable (t_delimiter, &t_list);
258+
259+ uindex_t t_count = MCArrayGetCount (p_array);
260+ combine_int_indexed_array_t t_lisctxt;
261+ bool t_success;
262+
263+ t_lisctxt . elements = nil;
264+ t_lisctxt . index = 0 ;
265+ t_lisctxt . converter = &ctxt;
266+ t_success = MCMemoryNewArray (t_count, t_lisctxt . elements);
267+
268+ if (t_success)
269+ {
270+ if (MCArrayApply (p_array, list_int_indexed_array_elements, &t_lisctxt))
271+ {
272+ bool t_valid_keys;
273+
274+ qsort (t_lisctxt . elements, t_count, sizeof (array_element_t ), compare_int_indexed_elements);
275+
276+ // Combine by row/column is only valid if all the indices are consecutive numbers
277+ // Otherwise, an empty string is returned - no error
278+ index_t t_last_index;
279+ t_valid_keys = true ;
280+ t_last_index = 0 ;
281+ for (int i = 0 ; i < t_count && t_valid_keys; ++i)
282+ {
283+ if (!t_last_index)
284+ t_last_index = t_lisctxt . elements[i] . key;
285+ else
286+ t_valid_keys = ++t_last_index == t_lisctxt . elements[i] . key;
287+ }
288+
289+ if (t_valid_keys)
290+ {
291+ for (int i = 0 ; i < t_count && t_success; ++i)
292+ {
293+ MCAutoStringRef t_string;
294+
295+ if (t_lisctxt . elements[i] . key == 0 ) // The index 0 is ignored
296+ continue ;
297+
298+ if (ctxt . ConvertToString (t_lisctxt . elements[i] . value, &t_string))
299+ t_success = MCListAppend (*t_list, *t_string);
300+ else
301+ t_success = false ;
302+ }
303+ }
304+ }
305+ MCMemoryDeleteArray (t_lisctxt . elements);
306+ }
307+
308+ if (t_success && MCListCopyAsString (*t_list, r_string))
309+ return ;
310+
311+ ctxt . Throw ();
157312}
158313
159314void MCArraysExecCombineAsSet (MCExecContext& ctxt, MCArrayRef p_array, MCStringRef p_element_delimiter, MCStringRef& r_string)
0 commit comments