Есть быстрый и грязный ответ и правильный ответ
Используйте list?.elementAt(
для безопасного доступа к элементу списка
Widget build(context) {
try{
if (isFirst == true) {
fetchImage();
fetchCategories(context);
isFirst = false;
}
}catch(Exception){
}
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: Text('Lets see images!'),
),
body: new Column(
children: [
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
new InkResponse(
child: new Column(
children: [
Padding(
padding: EdgeInsets.all(10.0),
child: new Image.asset(
catimages?.elementAt(0) ?? "",
width: 60.0,
height: 60.0,
),
),
new Text(
categoriesText?.elementAt(0) ?? "",
style: TextStyle(color: Colors.white),
),
],
),
onTap: () {
debugPrint("on tv clikced");
widget.fetchApI.fetchSubCategories(context, 6);
}),
new InkResponse(
child: new Column(
children: [
Padding(
padding: EdgeInsets.all(10.0),
child: new Image.asset(
catimages?.elementAt(1) ?? "",
width: 60.0,
height: 60.0,
),
),
new Text(
categoriesText?.elementAt(1) ?? "",
style: TextStyle(color: Colors.white),
),
],
),
onTap: () {
debugPrint("on moview clicked");
widget. fetchApI.fetchSubCategories(context, 7);
},
),
new InkResponse(
child: new Column(
children: [
Padding(
padding: EdgeInsets.all(10.0),
child: new Image.asset(
catimages?.elementAt(2) ?? "",
width: 60.0,
height: 60.0,
),
),
new Text(
categoriesText?.elementAt(2) ?? "",
style: TextStyle(color: Colors.white),
),
],
),
onTap: () {
debugPrint("on news clicked");
widget.fetchApI.fetchSubCategories(context, 10);
},
),
new InkResponse(
child: new Column(
children: [
Padding(
padding: EdgeInsets.all(10.0),
child: new Image.asset(catimages?.elementAt(3) ?? "",
width: 60.0, height: 60.0),
),
new Text(
categoriesText?.elementAt(3) ?? "",
style: TextStyle(color: Colors.white),
),
],
),
onTap: () {
debugPrint('on shows clicked');
widget.fetchApI.fetchSubCategories(context, 8);
},
),
new InkResponse(
child: new Column(
children: [
Padding(
padding: EdgeInsets.all(10.0),
child: new Image.asset('assets/live_icon.png',
width: 60.0, height: 60.0),
),
new Text(
'Live',
style: TextStyle(color: Colors.white),
),
],
),
onTap: () {
debugPrint('on live clicked');
},
),
],
),
ImageList(images,widget.fetchApI),
],
),
),
);
}
}
Честно говоря, если бы я пересмотрел этот код, даже если бы он работал незаметно, я бы отклонил это изменение, потому что структура / паттерн, который использует этот код, довольно плоха.
Пожалуйста, используйте вместо этого FutureBuilder , StreamBuilder или ValueListenableBuilder , но вам нужно предоставить больше кода (особенно fetchImage
и fetchCategories
) для нас, чтобы помочь.
I would first and foremost start using pattern-matching.
areListsEqual :: Eq a => [a] -> [a] -> Bool
areListsEqual [ ] [ ] = True
areListsEqual [ ] _ = False
areListsEqual _ [ ] = False
areListsEqual (x:xs) (y:ys) = x == y && areListsEqual xs ys
Note how much more readable this is, when head
and tail
is avoided.
charlieSort :: Eq a => [[a]] -> [[a]]
charlieSort [ ] = []
charlieSort [x ] = [x]
charlieSort xs@(first:second:theRest)
| areListsEqual xs wip = wip
| otherwise = charlieSort wip
where
swapPairIfNeeded a b
| length a >= length b = [second,first]
| otherwise = [first,second]
modifiedPair = swapPairIfNeeded first second
wip = take 1 modifiedPair ++ charlieSort (drop 1 modifiedPair ++ theRest)
I changed the if
-then
-else
to a guard for slightly improved readability
(YMMV). Instead of checking that the list has at least two elements with a
call to length
we use pattern-matching, which also allows us to name
first
,second
,theRest
directly. The name @ pattern
pattern both
matches the input against pattern
and names the whole input as name
.
Now, I want to avoid using take
and drop
for extracting the two elements
of modifiedPair
, so the last two lines are changed into
[shorter,longer] = swapPairIfNeeded first second
wip = [shorter] ++ charlieSort ([longer] ++ theRest)
where you could write the last line as
wip = shorter : charlieSort (longer : theRest)
if you preferred. But why should swapPairIfNeeded
return the shorter
and
the longer
of the first
and second
list in a list ? Why not use a
pair like
swapPairIfNeeded a b
| length a >= length b = (second,first)
| otherwise = (first,second)
(shorter,longer) = swapPairIfNeeded first second
? In most circumstances, it is better to use tuples for fixed number of
values (possibly of differing types) and to use lists for variable number of
values (necessarily of same type). But it seems strange that
swapPairIfNeeded
compares its arguments a
and b
, but then returns
first
and second
anyway. In this case, instead of letting it return a
and b
in a pair, I will remove swapPairIfNeeded
altogether instead :
(shorter,longer)
| length first >= length second = (second,first)
| otherwise = (first,second)
"unfolding" the body of swapPairIfNeeded
into the definition of
(shorter,longer)
.
So now the code of charlieSort
looks like
charlieSort :: Eq a => [[a]] -> [[a]]
charlieSort [ ] = []
charlieSort [x ] = [x]
charlieSort xs@(first:second:theRest)
| areListsEqual xs wip = wip
| otherwise = charlieSort wip
where
(shorter,longer)
| length first >= length second = (second,first)
| otherwise = (first,second)
wip = shorter : charlieSort (longer : theRest)
Finally, I should remark that charlieSort
doesn't really implement
bubble-sort, because the recursive call to charlieSort
will not only
make one "bubble-up" pass along the list, but also fully sort the list
longer : theRest
, so that all that has to be done after this recursive call
(before returning one "level up") is to possibly percolate shorter
to its
rightful place.
You don't need the areListsEqual
function. You can compare lists with the (==)
function. And I'd use a quicksort rather than bubblesort. Here's a solution that I think uses only what you should have learned so far.
charlieSort :: (Eq a) => [[a]] -> [[a]]
charlieSort [] = []
charlieSort (x:xs) = charlieSort (filter (cmpLen (>) x) xs) ++ [x] ++
charlieSort (filter (cmpLen (<=) x) xs)
where filter _ [] = []
filter p (x:xs) = (if (p x) then (x:) else id) (filter p xs)
cmpLen f x y = f (length x) (length y)
ИМХО обычно UPXing не имеет смысла, но причины изложены выше, в основном, память дороже, чем диск.
Эрик: заглушка LZMA может быть больше. Даже если алгоритм лучше, он не всегда является чистым плюсом.
Менее двух десятых от одного процента строк исходного текста в компиляторе Glasgow Haskell упоминают «head», и, говоря о них, примерно половина находится в строковых литералах или комментариях. Это примерно одно использование 'head' на каждые 1500 строк кода.)I'm on chapter 8, so I'm no old hand, but I'd prefer
areListsEqual x:xs y:ys = (x == y) && (areListsEqual xs ys)
areListsEqual [] [] = True
areListsEqual _ _ = False
It seems a bit more in line with Haskell style.
Similarly,
charlieSort [] = []
charlieSort (x:[]) = [x]
charlieSort (x1:x2:xs) = blah blah
swapPairIfNeed works as is because you only call it with first and second as its arguments (in that order), but you probably meant
swapPairIfNeed a b = if (length a >= length b)
then [b, a]
else [a, b]
In fact, I prefer the third case of charlieSort to look like
charlieSort (x1:x2:xs) = if not (areListsEqual x1:x2:xs wip)
then charlieSort wip
else wip
where swapPairIfNeeded a b = if (length a >= length b)
then (b, a)
else (a, b)
wip = f (swapPairIfNeeded first second)
f (a, b) = a : (charlieSort b:xs)
I think this was all covered by chapter 3.
Now, let's examine the algorithm. Even holding ourselves to bubble sort, there's no need to check the whole list after sorting. Instead, we can swap the first two elements if necessary, then sort the tail of the list. If the head is shorter than the head of the sorted tail, we're done.
charlieSort (x1:x2:xs) = if (length a <= length (head sortedTail))
then a : sortedTail
else charlieSort (a : sortedTail)
where sortedTail = charlieSort (b:xs)
(a, b) = if (length x1 >= length x2)
then (x2, x1)
else (x1, x2)
Вы утверждаете, что сортировка по пузырькам - самый простой алгоритм сортировки, но здесь это не совсем так. Пузырьковая сортировка отлично подходит для массивов, где вы индексируете их линейно. Для связанных списков в Haskell сортировку вставкой на самом деле гораздо красивее.
Давайте начнем с функции insert
:
winsert :: [a] -> [[a]] -> [[a]]
winsert x [] = [x]
winsert x (y:ys)
| length x < length y = x : y : ys
| otherwise = y : winsert x ys
x
x , то x
находится в начале списка
y
, а Хвост состоит из x
, вставляемых где-то в ys
. Далее, у нас есть фактическая функция сортировки:
wsort :: [[a]] -> [[a]]
wsort [] = []
wsort [x] = [x]
wsort (x:xs) = winsert x (wsort xs)
xs
, затем вставьте x
в теперь отсортированный xs
Интересно, что путем изменения winsert
для получения функции в качестве аргумента (вместо длины
), wsort
можно использовать для сортировки на основе по всем видам критериев. Попробуйте создать список, который сортирует список списков на основе суммы каждого подсписка.